Использование Awk или Sed, чтобы прикрепить оператор в конце определенной строки

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

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

_cell_length_a

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

_cell_length_a 5.3827

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

3 ответа

Поскольку ветеранская утилита 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 гарантирует отсутствие ошибок при отсутствии совпадений.
    • Обратите внимание, что $ является \ - защищен от интерпретации оболочкой внутри этого документа (не является строго необходимым в данном случае, но является хорошей практикой).
  • s//& $a/... // повторяет поиск последнего использованного регулярного выражения в соответствующей строке и заменяет совпадение на себя (&), затем пробел и значение переменной $a,
    • Обратите внимание, что с момента открытия разделителя (EOF) здесь-документа не заключены в кавычки, имеют место расширения переменных оболочки; по сути, содержимое обрабатывается оболочкой как содержимое строки в двойных кавычках.
  • w записывает измененный буфер обратно во входной файл.
    • Для отладки используйте ,p на месте w чтобы печатать только измененный буфер, не записывая его обратно в файл.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

где,

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

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

s/find/replace/

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

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

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

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

Другие вопросы по тегам