Я пытаюсь заменить путь во входном файле.
#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!'