Я совершенно не знаком с сценариями bash. У меня есть текстовый файл (назовите его geom.txt
), который я использую, который выглядит следующим образом:
2
C -0.6165934086165 -0.35599823933468 0.00000000 0.8466
C 0.6165934086165 0.35599823933468 0.00000000 0.8466
lattice_vector 2.46670923 0.00000000 0.00000000
lattice_vector 1.23286602 2.13599798 0.00000000
lattice_vector 0.00000000 0.00000000 40
Я хотел бы написать сценарий, который добавит строку между строками 1 и 2, чтобы получить такой результат:
2
C -0.6165934086165 -0.35599823933468 0.00000000 0.8466
C 0.6165934086165 0.35599823933468 0.00000000 0.8466
lattice_vector 2.46670923 0.00000000 0.00000000
lattice_vector 1.23286602 2.13599798 0.00000000
lattice_vector 0.00000000 0.00000000 40
Более того, я хочу сделать это общим, чтобы любой входной файл предыдущей формы добавлял пустую строку между строками 1 и 2. Я знаю, что это базовый вариант, но мне нужна помощь! Спасибо!
3 ответа
Используя gnu sed
:
sed -i.bak '2s/^/\n/' file
Использование awk
:
awk 'NR==2{print "\n" $0; next}1' file
Использование non-gnu sed
sed -i.bak $'2s/^/\\\n/' file
ИЛИ еще:
eol=$'\n'
sed -i.bak "2s/^/\\$eol/" file
Наконец, вот чистый способ BASH:
c=0
while IFS= read -r line; do
(( c++ == 1 )) && echo
echo "$line"
done < file
Вы можете использовать vim
для достижения своей цели.
vim -c 1 -c "normal o" -c wq geom.txt
Или вы можете сделать это в простом цикле while:
let count=0 # set a simple integer to test
:> tmpfile # create or truncate tmpfile
while read line || test -n "$line"; do
echo "$line" >> tmpfile # write each line to tmpfile
# if this is the first line, add a newline and increment counter
test "$count" -eq 0 && echo "" >> tmpfile && ((count+=1))
done <"$1"
# when all lines written to tmpfile copy tmpfile to filename given as arg, remove tmpfile
cp tmpfile "$1" && rm -f tmpfile
let
с count=0
- с или без let
count
будет строковой переменной; если вы хотите создать целочисленную переменную, используйте declare -i count=0
(что также прояснит ваше намерение). Обратите внимание, однако, что благодаря утиной печати тип редко имеет значение. При использовании ((...))
вы уже использовали не-POSIX синтаксис bash
, так почему бы не использовать [[ ... ]]
или ((...))
вместо test
? Например, test "$count" -eq 0 && echo "" >> tmpfile && ((count+=1))
можно упростить до (( count++ == 0 )) && echo >> tmpfile
.
sed
или awk
, намного, намного быстрее.
when it is referenced
, или, когда переменной, которой присвоен целочисленный атрибут using declare -i
, присваивается значение. (man bash) Согласен, объявлено ли -i или нет, это редко имеет значение. Цикл может иметь свои недостатки для больших файлов, но для всего, что меньше нескольких тысяч строк, цикл будет таким же быстрым или даже быстрее, чем запуск дополнительного приложения для этого.
sed
(sed $'2s/^/\\\n/' file
): решение sed
начинает работать быстрее при 50. строки (той же длины, что и пример данных в вопросе, в моей системе OS X 10.9.4). Не научный тест, но он дает вам ощущение, что порог, вероятно, ниже, чем вы думаете. Хотя я согласен с тем, что это не имеет значения для небольших файлов, обычно стоит добавить заявление об отказе от ответственности при публикации решения с циклом поверх строк только для оболочки. Что касается вашего конкретного кода: вы должны заключить в двойные кавычки $line
в test -n $line
.
sed
с одним вызовом из команды line мало что может замедлить его работу, но при повторном вызове, скажем, из скрипта, любое преимущество быстро исчезает. Спасибо, что нашли время, чтобы поставить цифры к нему. Если я найду что-нибудь примечательное, я оставлю заметку здесь.
Похожие вопросы
Новые вопросы
bash
Этот тег предназначен для вопросов о сценариях, написанных для командной оболочки Bash. Сценарии оболочки с синтаксисом или другими ошибками, пожалуйста, проверьте их на https://shellcheck.net, прежде чем публиковать здесь. Вопросы об интерактивном использовании Bash, скорее всего, будут актуальны на Unix & Linux Stack Exchange или Super User, чем на Stack Overflow.
:P
+1
за это предварительное мышление.[[ $c == 1 ]] && echo ... ... ((c++))
можно упростить до(( c++ == 1 )) && echo
.