linuxの文字列置換に関する質問です。

シェルスクリプトで、ファイル内の文字列を次のように置換したいのですが、うまくいきません。

--------
対象ファイル
myfile

置換前
&hogehoge("barbar", $bazbaz);

置換後
&hogehoge("barbar", "$chomechome, $bazbaz");
&hogehoge("qux", $bazbaz);
--------

sedで複数行の置換をするのでは?ということまでは分かり、以下のようなスクリプトを書きましたが、思った通りの挙動になりません。指定したmyfile内の置換前の文字列1行を置換後の2行に変換するためのスクリプトを教えて下さい。

test.sh
--------
#!/bin/sh
LF=$(printf '\\\012_')
LF=${LF%_}

echo "hogehoge\nfoo\nbar" | sed 's/\\n/'"$LF"'/g'
sed -i 's/&hogehoge("barbar", $bazbaz);/&hogehoge("barbar", "$chomechome, $bazbaz");\n &hogehoge("qux", $bazbaz);/g' ./myfile
--------

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2022/04/26 09:54:30
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:kazuihitoshi No.2

回答回数1ベストアンサー獲得回数1

ポイント250pt

やりとりから、&hogehoge("barbar", $bazbaz);より &hogehoge と パラメータである "barbar", $bazbazを認識したうえで、2行分の変換結果を得たいとのことと理解しました。

awk の方が汎用性があると思いますが(構文解析も可能ですが)今回は冒頭からsedでの実施を期待されているようでしたので、次のものを作ってみました。

最初の質問内容と、2回目の例題に対応できる仕様になっています。

スクリプトと動作結果を以下に示します。

WSL2上のUbuntu20.04 bash にて動作検証


sed -r 's/\&hogehoge\(([\"|\$|A-z|0-9]+).*[, \t]([\"|\$A-z|0-9]+).*/\&hogehoge(\1,\"\$chromechrome,\2);\n\&hogehoge(\"qux\",\2);/' myfile.txt



結果

&hogehoge("barbar","$chromechrome,$bazbaz);

&hogehoge("qux",$bazbaz);



sed -r 's/\&hogehoge\(([\"|\$|A-z|0-9]+).*[, \t]([\"|\$A-z|0-9]+).*/\&hogehoge(\1,\"\$chromechrome,\2);\n\&hogehoge(\"qux\",\2);/' myfile2.txt


myfile2.txt

if (&aaaaa($chome) ) {

&hogehoge("barbar", $bazbaz);

}

else {

&hogehoge("barbar-to", "$chome, $bazbaz");

}


結果

if (&aaaaa($chome) ) {

&hogehoge("barbar","$chromechrome,$bazbaz);

&hogehoge("qux",$bazbaz);

}

else {

&hogehoge("barbar,"$chromechrome,$bazbaz");

&hogehoge("qux",$bazbaz");

}

sedでの文字列抽出は以下を参考にしました。

https://qiita.com/koara-local/items/2911bd81df2420a420ad

その他の回答1件)

id:a-kuma3 No.1

回答回数4973ベストアンサー獲得回数2154

ポイント50pt

awk を使った方が簡単な事例かと思います。


#! /bin/sh 

cat myfile | gawk '
/&hogehoge\("barbar", \$bazbaz\);/ {
  print "&hogehoge(\"barbar\", \"$chomechome, $bazbaz\");"
  print "&hogehoge(\"qux\", $bazbaz);"
  next
}
{
  print $0
}
'

質問の文面にある &hogehoge("barbar", $bazbaz); な行を、固定の 2行で出力し、それ以外の行はそのまま出力します。



質問の文面にあるやつを極力活かすなら、以下のような感じになるかと。

#!/bin/sh
LF=$(printf '\\\012_')
LF=${LF%_}

echo "hogehoge\nfoo\nbar" | sed 's/\\n/'"$LF"'/g'
sed -i 's/&hogehoge("barbar", \$bazbaz);/\&hogehoge("barbar", "$chomechome, $bazbaz");\n\&hogehoge("qux", $bazbaz);/g' ./myfile
id:kazuihitoshi No.2

回答回数1ベストアンサー獲得回数1ここでベストアンサー

ポイント250pt

やりとりから、&hogehoge("barbar", $bazbaz);より &hogehoge と パラメータである "barbar", $bazbazを認識したうえで、2行分の変換結果を得たいとのことと理解しました。

awk の方が汎用性があると思いますが(構文解析も可能ですが)今回は冒頭からsedでの実施を期待されているようでしたので、次のものを作ってみました。

最初の質問内容と、2回目の例題に対応できる仕様になっています。

スクリプトと動作結果を以下に示します。

WSL2上のUbuntu20.04 bash にて動作検証


sed -r 's/\&hogehoge\(([\"|\$|A-z|0-9]+).*[, \t]([\"|\$A-z|0-9]+).*/\&hogehoge(\1,\"\$chromechrome,\2);\n\&hogehoge(\"qux\",\2);/' myfile.txt



結果

&hogehoge("barbar","$chromechrome,$bazbaz);

&hogehoge("qux",$bazbaz);



sed -r 's/\&hogehoge\(([\"|\$|A-z|0-9]+).*[, \t]([\"|\$A-z|0-9]+).*/\&hogehoge(\1,\"\$chromechrome,\2);\n\&hogehoge(\"qux\",\2);/' myfile2.txt


myfile2.txt

if (&aaaaa($chome) ) {

&hogehoge("barbar", $bazbaz);

}

else {

&hogehoge("barbar-to", "$chome, $bazbaz");

}


結果

if (&aaaaa($chome) ) {

&hogehoge("barbar","$chromechrome,$bazbaz);

&hogehoge("qux",$bazbaz);

}

else {

&hogehoge("barbar,"$chromechrome,$bazbaz");

&hogehoge("qux",$bazbaz");

}

sedでの文字列抽出は以下を参考にしました。

https://qiita.com/koara-local/items/2911bd81df2420a420ad

  • id:ISONOnamihei
    ありがとうございます。awkの事例でうまくいきそうですが、myfileがこのような記述の場合、置換されないようです。

    if (&aaaaa($chome) ) {
    &hogehoge("barbar", $bazbaz);
    }
    else {
    &hogehoge("barbar-to", "$chome, $bazbaz");
    }



    また、myfileを上書きする形で処理を終えられればと思います。このような形で上書きできそうと言うことは分かりましたが、ヒットした部分だけ置換する方法が分かりませんでした。お力添え頂けると助かります。

    awk '(PROGRAM)' testfile.txt > testfile.tmp && mv testfile.tmp testfile.txt
  • id:a-kuma3
    >myfileがこのような記述の場合、置換されないようです。

    多分、else 句の中のことを言ってるのだと思いますけれども、
    それは、質問の文面からは全く分かりません。

    回答では、あくまでも、"&hogehoge("barbar", $bazbaz);" の文字列を置き換えているだけです。

    どこが固定で、どこが可変なのかを明示しないと、誰にも回答できません。
  • id:ISONOnamihei
    a-kuma3様、仮面なんとか様

    前提を欠いておりまして、申し訳ございませんでした。お恥ずかしながら、
    実際にスクリプトを走らせた時に質問の内容が正確さに欠けていたことが分かりました。
    もし追加でご回答頂けるのであれば、こちらでお願い出来るでしょうか。
    前任者が退職しており、一人担当のため誰にも頼れない状況で、こちらの回答は大変助かっています。

    置換対象
    myfile

    やりたいこと
    if句の&hogehoge("barbar-to", $bazbaz);の1行を、
    &hogehoge("barbar-to","$chromechrome,$bazbaz");と&hogehoge("qux",$bazbaz);の2行に変換したい。
    else句は変更しない。
    仮面なんとか様のコマンドでは、else句の&hogehoge("barbar-to", "$chome, $bazbaz");が置換されていますが、
    そこが置換されなければ、求める結果になります。

    置換前
    if (&aaaaa($chome) ) {
    &hogehoge("barbar-to", $bazbaz);
    }
    else {
    &hogehoge("barbar-to", "$chome, $bazbaz");
    }

    置換後
    if (&aaaaa($chome) ) {
    &hogehoge("barbar-to","$chromechrome,$bazbaz");
    &hogehoge("qux",$bazbaz);
    }
    else {
    &hogehoge("barbar-to", "$chome, $bazbaz");
    }
  • id:kazuihitoshi
    最初の一つだけ置換対象にするのですね。
    その場合は、0行目から置換対象の行を絞って置換すればよいので、次の形でよいかと。

    sed -r '0,/\&hogehoge\(/ s/\&hogehoge\(([\"|\$|A-z|0-9]+).*[, \t]([\"|\$A-z|0-9]+).*/\&hogehoge(\1,\"\$chromechrome,\2);\n\&hogehoge(\"qux\",\2);/' myfile.txt


    結果
    if (&aaaaa($chome) ) {
    &hogehoge("barbar,"$chromechrome,$bazbaz);
    &hogehoge("qux",$bazbaz);
    }
    else {
    &hogehoge("barbar-to", "$chome, $bazbaz");
    }

    参考にさせてもらった記事
    https://www.greptips.com/posts/1235/#:~:text=%E4%B8%80%E7%95%AA%E3%81%AF%E3%81%98%E3%82%81%E3%81%A0%E3%81%91%E7%BD%AE%E6%8F%9B,%E7%BD%AE%E6%8F%9B%E5%BE%8C%2F'%20%E3%81%A8%E3%81%99%E3%82%8B%E3%80%82
  • id:ISONOnamihei
    仮面なんとか様
    ありがとうございます。ほぼ思っているとおりの結果になりました。
    ただ、if句のbarbar-toは置換後もbarbar-toのままで、barbarに置換されるとまずいため、頂いたスクリプトを元に修正しました。

    if (&aaaaa($chome) ) {
    &hogehoge("barbar-to","$chromechrome,$bazbaz");
    &hogehoge("qux",$bazbaz);
    }
    else {
    &hogehoge("barbar-to", "$chome, $bazbaz");
    }

    a-kuma3もご協力下さいましてありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません