Использование 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
обрабатывает этот сценарий правильно.
- Осторожно: BSD
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-символы или метасимволы, с которыми вам нужно обращаться особенно, если ваша строка содержит их.