Как заменить строку во входном файле с помощью sed/awk/perl

Как заменить строку во входном файле с помощью sed/awk/perl

Я пытаюсь заменить путь во входном файле.

    #include "../../../Plumed.h"         #### this is old patch in input 

    #include "/usr/local/include/Plumed.h  #### this should be the new path

После просмотра ранее отвеченного вопроса (https://stackoverflow.com/questions/11245144/replace-whole-line-content-a-string-using-sed).

Я попробовал это.

    sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg


    perl -i -pe 's/../../../Plumed.h/usr/local/include/Plumed.h/g' ../dist0.xvg

Я думаю, что sed/perl путается, но я не уверен, как это преодолеть. Любая помощь будет оценена по достоинству.

решение1

тл,др:

Использовать:

sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg

Несколько комментариев по вашей попытке выполнить команду Sed:

sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg
  • -iнепереносимо, поэтому, по всей видимости, вы используете GNU Sed.

    В BSD Sed также есть -iпереключатель, но расширение резервной копии является обязательным аргументом, поэтому для изменения файла без сохранения резервной копии в BSD Sed требуется -i ''.

    В других версиях Sed -iпереключатель может отсутствовать вообще.

  • Регулярное выражение здесь /../../../Plumed.h/содержит несколько копий разделителя регулярного выражения.

    Обычное решение этой проблемы — экранировать разделитель:

    /..\/..\/..\/Plumed.h/
    

    Однако есть малоизвестный факт о Sed, что вы можете использоватьлюбойсимвол для разделителя регулярных выражений (не только в sкоманде), если вы экранируете первый экземпляр обратной косой чертой. (Ну, почти любой — обратная косая черта или новая строка не допускаются.)

    Цитата:Спецификации POSIXнапрямую:

    В контекстном адресе конструкция " \cBREc", гдеслюбой символ, отличный от <backslash>или <newline>, должен быть идентичен " /BRE/". Если символ, обозначенныйспоявляется после <backslash>, то он должен считаться тем литеральным символом, который не должен завершать BRE. Например, в адресе контекста " \xabc\xdefx", второйИксобозначает себя, так что BRE — это « abcxdef».

    Поэтому, чтобы избежать «синдрома уткнувшихся зубочисток», обратите внимание, что следующие два регулярных выражения эквивалентны:

    /..\/..\/..\/Plumed.h/
    \:../../../Plumed.h:
    

    Обратите внимание, я сказал «эквивалентный».нетправильно. Это подводит меня к следующему пункту, упущенному в каждом другом ответе:

  • Точка ( .) в регулярном выражении обозначаетлюбой персонаж.

    Если вы хотите сопоставить только буквальную точку, вы можете либо экранировать ее с помощью обратной косой черты, либо вставить ее в класс символов, как в [.].

    Таким образом, чтобы соответствовать только буквальным точкам, регулярное выражение должно выглядеть примерно так:

    \:\.\./\.\./\.\./Plumed\.h:
    

    Вот вам и избегание наклонных зубочисток.

    Вы также можете использовать, пожалуй, более удобочитаемую форму:

    \:[.][.]/[.][.]/[.][.]/Plumed[.]h:
    
  • Команда cизменяетвся линия, а не только часть строки, совпадающую с регулярным выражением.

    Используйте sкоманду, чтобы изменить только часть строки.

    Примечательно, что при использовании этой sкоманды вам не нужно экранировать первый разделитель регулярного выражения (даже если в качестве разделителя используется необычный символ), как это делается при использовании альтернативного разделителя в адресе.

    Кроме того, что касается cкоманды, стоит знать, что включение нового текста в ту же строку, что и c\является расширением GNU и непереносимо.


Объединив все это вместе, вы можете использовать sкоманду следующим образом:

sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg

Или, если вы хотите быть еще более явными, вы можете использовать закрепленное регулярное выражение и cкоманду hange, чтобы изменить только всю строку:

sed -i '\:^#include "\.\./\.\./\.\./Plumed\.h"$:c\#include "/usr/local/include/Plumed.h"' ../dist0.xvg

решение2

Если вы используете /as в качестве разделителя с sed, то решением может быть:

sed -i 's/..\/..\/..\/Plumed.h/\/usr\/local\/include\/Plumed.h/g' file

или вы можете использовать другой разделитель /, например ::

sed -i 's:../../../Plumed.h:/usr/local/include/Plumed.h:g' file

Другой способ awk:

awk '{ gsub("../../../Plumed.h","/usr/local/include/Plumed.h"); print $0}' file

решение3

Эта команда сработала для меня:

     sed -i 's#include "../../../Plumed.h"#include "/usr/local/include/Plumed.h"#g'

решение4

Используйте восклицательный знак, если в тексте много косых черт:

sed -e 's!../../../Plumed.h!/usr/local/include/Plumed.h!'

Связанный контент