Использование Awk или Sed для привязки к заявлению в конце определенной строки

У меня есть файл с именем poscar1.cif, и я хотел бы вставить содержимое переменной в определенную строку в этом файле.

Например, строка 24, которая в настоящее время читает:

_cell_length_a

Я хотел бы добавить содержимое моей переменной a (определенную в моей функции как a=5.3827), так что теперь строка читает:

_cell_length_a 5.3827

Есть ли способ сделать это с помощью sed или awk? Я использую bash script, чтобы выполнить это (полный script слишком велик для публикации, к сожалению).

Ответ 1

Так как утилита ed больше не получает достаточного внимания:

a=5.3827

ed -s poscar1.cif <<EOF 
g/^_cell_length_a\$/ s//& $a/
w
EOF

ed действительно редактирует файл на месте, в отличие от sed с его опцией -i [1].

sed заимствовал множество функций от ed, поэтому существует существенное перекрытие функциональности, но есть также важные отличия, некоторые из которых здесь.

  • -s подавляет сообщения о статусе ed.
  • poscar1.cif - это входной файл для редактирования на месте.
  • <<EOF ... - здесь-документ, который содержит команды для ed - ed, требует, чтобы его команды поступали из stdin и каждая команда должна быть в отдельной строке.
  • g/^_cell_length_a\$/... является (базовым) регулярным выражением (регулярным выражением), которое соответствует всем строкам, содержащим _cell_length_a - g, чтобы не сообщалось об ошибке, если совпадение вообще отсутствует.
    • Обратите внимание, что $ является \ -escaped, чтобы защитить его от интерпретации оболочкой внутри этого документа (не обязательно в этом случае, но хорошей практикой).
  • s//& $a/... // повторяет поиск последнего используемого регулярного выражения в соответствующей строке и заменяет совпадение с самим собой (&), за которым следует пробел и значение переменной $a.
    • Обратите внимание, что, поскольку открывающий разделитель (EOF) здесь-документа некотируется, происходит разложение переменных оболочки DO; по сути, содержимое обрабатывается оболочкой подобно содержимому строки с двумя кавычками.
  • w записывает измененный буфер обратно во входной файл.
    • Для отладки используйте ,p вместо w, чтобы печатать только модифицированный буфер, не записывая его обратно в файл.

[1] Обновление на месте:

Точнее, ed сохраняет существующий файл inode, что гарантирует сохранение всех атрибутов файла.
Однако он не перезаписывает отдельные байты существующего файла, но считывает весь файл в буфер в памяти и записывает весь буфер в файл при его запросе.
Это делает ed пригодным только для файлов, достаточно малых для чтения в памяти в целом.

В отличие от sed -i (GNU и BSD sed), его аналог GNU 4.1 +, awk -i inplace, а также perl -i заменить исходный файл на новый, что означает, что они:

  • уничтожить символические ссылки (!) - если входной файл был символической ссылкой, он заменяется обычным файлом с тем же именем
    • Общий сценарий, в котором это имеет значение: скажем, файл инициализации вашей оболочки ~/.bashrc является символической ссылкой на файл в другом месте, который вы держите под контролем источника; затем вы устанавливаете инструмент, который использует sed -i для изменения ~/.bashrc, в результате чего он заменяется обычным файлом, и ссылка на вашу версию с контролируемым источником не работает.
    • Что еще, поведение BSD sed даже представляет угрозу безопасности (см. ниже).
  • do не сохранить дату создания файла (если поддерживается, например, в OSX)
  • они делают, однако

    • сохранить расширенные атрибуты (если поддерживается, например, в OSX)
    • сохранить файлы разрешений

      • Внимание: BSD sed представляет риск безопасности по отношению к символическим ссылкам (поведение по-прежнему присутствует в версии версии FreeBSD 10):
        • Разрешения symlink копируются в файл замены, а не в цель symlink. Поскольку symlinks получает исполняемые разрешения по умолчанию, , вы всегда будете иметь исполняемый файл, независимо от того, был ли входной файл исполняемым или нет.
      • К счастью, GNU sed корректно обрабатывает этот сценарий.

sed, gawk и perl могли бы устранить проблемы выше, выполнив дополнительные шаги, но там одна вещь, которая может быть обеспечена только в том случае, если исходный индекс сохраняется, а ed выполняет

Когда файл отслеживается для изменений по его номеру inode (например, с tail -f), не сохраняя разрывы inode, которые контролируют.

Ответ 2

Вы можете использовать sed для этого, в зависимости от вашего ответа на вопрос dawg, как

sed -i -e '24s/$/5.3827/' poscar1.cif

или если это шаблон

sed -i -e '/_cell_length_a/s/$/5.3827/' poscar1.cif

Первый идет в строку с заданным номером, а позже будет применяться к любой строке, которая соответствует шаблону в первом наборе косой черты. В любом случае он "заменит" конец строки значением между двумя последними чертами.

Ответ 3

Используя ваш пример, вы можете сделать что-то вроде этого:

sed -i 's/\(_cell_length_a\)/\1 5.3827/' poscar1.cif

где

  • Опция -i указывает, что нужно редактировать файл вместо создания копии
  • фанки, выглядящая цитата, является строкой, определяющей регулярное выражение aka regex
  • poscar1.cif - это файл

Синтаксис регулярного выражения трудно прочитать. Основной формат для поиска и замены:

s/find/replace/

Где find - текст строки, которую вы ищете, и replace - это текст для замены этого текста.

Если мы хотим использовать часть строки поиска в нашей замене, мы группируем ее, окружая ее \( и \), а затем используйте \1 для ссылки на нее в заменяющей строке. Следующие добавления заменяют на любую строку, состоящую из find:

s/\(find\)/\1replace/

Имейте в виду, что есть специальные escape-символы или метасимволы, которые вам нужно обрабатывать, особенно если ваша строка содержит их.