如何使用 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-containing-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

TL,博士:

使用:

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 ''.

    -i其他版本的 Sed 可能根本没有开关。

  • 此处的正则表达式/../../../Plumed.h/包含正则表达式分隔符的多个副本。

    通常的解决方案是转义分隔符:

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

    然而,关于 Sed 有一个鲜为人知的事实,您可以使用任何s如果您反斜杠转义第一个实例,则为正则表达式分隔符(不仅仅是在命令中)。 (好吧,几乎任何 - 不允许反斜杠或换行符。)

    引用POSIX 规范直接地:

    在上下文地址中,构造“ \cBREc”,其中C是除<backslash>或以外的任何字符<newline>,应与“ /BRE/”相同。如果指定的字符C出现在 a 之后<backslash>,则应将其视为该文字字符,该字符不应终止 BRE。例如,在上下文地址“ \xabc\xdefx”中,第二个X代表它自己,因此 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

或者,如果您想更明确,您可以使用锚定正则表达式和change命令仅更改整行:

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

答案2

如果您将 用作/分隔符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!'

相关内容