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-including-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」は、c<backslash>または以外の文字は<newline>、「 」と同じになります/BRE/cが の後に現れる<backslash>場合、それはそのリテラル文字とみなされ、BREを終了しないものとする。例えば、コンテキストアドレス「\xabc\xdefx」では、2番目のバツそれ自体を表すので、BRE は「abcxdef」になります。

    したがって、「傾いたつまようじ症候群」を回避するには、次の 2 つの正規表現が同等であることに注意してください。

    /..\/..\/..\/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!'

関連情報