1

質問:

私はsedが初めてなので、シェルで次のコードを実行すると:

sed -e "/^\s<key>CHANNEL_NAME<\/key>$/{N;s/\(^\s<string>\).+\(<\/string>$\)/\1test\2}" Info.plist > test.plist

Sed でエラーが表示されます: "sed: 1: "/^\sCHANNEL_NAME<\ ...": エスケープされていない改行が置換パターン内にあります"

私の質問:「代替パターン内のエスケープされていない改行」とは正確にはどういう意味ですか?

Info.plist ファイルは次のようになります。

...
<key>CHANNEL_NAME</key>
<string>App Store</string>
...

みんなが質問に答えてくれてありがとう、ありがとう!


答え:

ありがとう@potong @dogbane @Beta!: )

それはココアのplistなので、これが私の最終的な解決策です:

sed '/<key>CHANNEL_NAME<\/key>/{N;s/\(<string>\).*\(<\/string>\)/\1test\2/;}' Info.plist > test.plist

チップ:

  1. 問題を解決するためのプロセス中に 2 つのエラーが発生しました。それらをここに入れます:
    • sed: 1: "/^\sCHANNEL_NAME<\ ...": 置換パターン内のエスケープされていない改行
    • sed: 1: "/CHANNEL_NAME</ke ...": 代替コマンドのフラグが正しくありません: '}'
  2. 私は最初のコードで非常に多くの間違いを犯します。
    • 「+」をエスケープしていません
    • 2/} で終わる必要があります」
    • 実際には 2/;} で終わる必要があります" (「;」が抜けているため、ヒント 1 で 2 番目のエラーが発生しました)
  3. ユーザー「n」または「N」はどちらも機能します。
  4. おそらくMacでは、「.+」(エスケープしても)が機能しないため、@potongが言ったように「..*」に変更する必要があります

コードを承認するための良いアドバイスは大歓迎です。次のすべての人にもう一度感謝します!

4

2 に答える 2

4

これはうまくいくかもしれません(GNU sed):

sed -e '/^\s*<key>CHANNEL_NAME<\/key>$/{n;s/^\(\s*<string>\).\+\(<\/string>\)$/\1test\2/}' Info.plist > test.plist

NB^\s*行の先頭に空白 () を許可し、一致した行を出力してから、置換コマンドの次の行の先頭を比較する必要があります。つまり、n代わりに を使用しNます。

または:

sed -e '/^ *<key>CHANNEL_NAME<\/key>$/!b' -e 'n' -e 's/^\( *<string>\)..*\(<\/string>\)$/\1test\2/' Info.plist > test.plist
于 2012-12-18T11:48:37.053 に答える
1

sedを学んでいるとおっしゃっていたので、sedは単一行での単純な置換のための優れたツールですが、それ以外の場合はawkを使用してください。

これがGNUawkソリューションです(必要に応じて1行に詰め込むことができます):

$ cat file
...
foo
<key>CHANNEL_NAME</key>
<string>App Store</string>
...
$
$ awk '
   found { $0=gensub(/(<string>).*(<\/string>)/,"\\1test\\2",""); found=0 }
   /<key>CHANNEL_NAME<\/key>/ { found=1 }
   { print $0 }
' file
...
foo
<key>CHANNEL_NAME</key>
<string>test</string>
...

sedソリューションと大差ないように見えますが、sedソリューションを変更して、出力に行番号を追加するなど、追加の処理を実行してみてください。

$ awk '
   found { $0=gensub(/(<string>).*(<\/string>)/,"\\1test\\2",""); found=0 }
   /<key>CHANNEL_NAME<\/key>/ { found=1 }
   { print NR, $0 }
' file
1 ...
2 foo
3 <key>CHANNEL_NAME</key>
4 <string>test</string>
5 ...

または、「文字列」の間のテキストを、ハードコードされた「テスト」ではなく、CHANNEL_NAMEの前の行の内容に置き換えます。

awk '
   found { $0=gensub(/(<string>).*(<\/string>)/,"\\1" rep "\\2",""); found=0 }
   /<key>CHANNEL_NAME<\/key>/ { found=1; rep=prev }
   { print $0; prev=$0 }
' file
...
foo
<key>CHANNEL_NAME</key>
<string>foo</string>
...

そして、おそらく一文字と句読点の悪夢のような組み合わせを含む、まったく別の解決策が必要であることがわかりますが、awkを使用すると、最初の解決策を強化するための簡単な調整です。

于 2012-12-19T13:41:09.383 に答える