バックスラッシュに渡された区切り文字を無視する方法は?

バックスラッシュに渡された区切り文字を無視する方法は?

次のユースケースがあります。

echo "some comment char '\;' embedded in strings   ; along with inline comments" \
| cut -d';' -f 1

私の考えでは:

some comment char ';' embedded in strings

私は得る:

some comment char '

このユースケースに示すように切り取るように構成された区切り文字を非表示にするにはどうすればよいですか?理想的には、カットはバックスラッシュを読んで尊重しますが、そうでない場合は他の方法はありますか?

答え1

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ echo "some comment char '\;' embedded in strings   ; along with inline comments" |
awk -F';' '{gsub(/\\\\/,RS); gsub(/\\;/,"\\\\"); gsub(/\\\\/,";",$1); gsub(RS,"\\",$1); print $1}'
some comment char ';' embedded in strings

そして借りる@Stéphaneの入力ファイルの例:

$ cat file
foo\;bar;baz
foo\\;bar;baz

$ awk -F';' '{gsub(/\\\\/,RS); gsub(/\\;/,"\\\\"); gsub(/\\\\/,";",$1); gsub(RS,"\\",$1); print $1}' file
foo;bar
foo\

より多くのフィールドを持つ行に展開します。

$ cat file
foo\;bar;baz
foo\\;bar;baz
foo\\;bar\;this\;that\\;baz;here\;and\;there

必要に応じて一部またはすべてのフィールドを印刷できます。ここでは、最初の行を最初に出力し、単一のフィールドを含む各出力行の先頭にフィールド番号を出力します。

$ awk -F';' '{print; gsub(/\\\\/,RS) gsub(/\\;/,"\\\\"); for (i=1; i<=NF; i++) { gsub(/\\\\/,";",$i); gsub(RS,"\\",$i); print "   " i, $i }; print "---" }' file
foo\;bar;baz
   1 foo;bar
   2 baz
---
foo\\;bar;baz
   1 foo\
   2 bar
   3 baz
---
foo\\;bar\;this\;that\\;baz;here\;and\;there
   1 foo\
   2 bar;this;that\
   3 baz
   4 here;and;there

上:

  1. \\現在の入力行()の各文字を$0改行文字(のデフォルト値RS)に変換します。これは改行文字で区切られたレコードには存在できない文字列なので、エスケープされた半分ではなく\\;入力バックスラッシュからエスケープされたものとして扱うことができます。 - 文字コロン、その後
  2. それぞれをに変換します\;。これは$ 0に存在できない文字列でもあります。なぜなら、それを削除するためにすべてsに変換するからです。$0\\RS;
  3. 修正操作の$0ために、awkは$0残りの各フィールドのフィールドに再分割され、;目的の文字列を入れて$1から
  4. \\上記の手順2で作成したすべてをthen$1に変換します。;
  5. RS上記の手順1で作成したすべての項目を$1再変換して\\から
  6. 私たちはフィールドを印刷します。$1

この方法は、RSPOSIXで定義されたすべてのリテラル文字列に対して機能し、RSGNU awkなどの一部のawkでサポートされている正規表現の場合は、正規表現に一致する正規表現メタ文字を持たない文字列を代替として提案します。RS

答え2

GNUgrepまたは互換機能を使用してください(非標準ですが、現在は非常に一般的な-oオプション)。

grep -Eo '^(\\.|[^\\;])*'

これはゼロ個以上の()1シーケンスを一致させて出力しo、その後にはエスケープだけでなくエスケープも含む単一文字()または行の先頭()以外のすべての文字が続きます。*\.;\\;^

例:

$ cat file
foo\;bar;baz
foo\\;bar;baz
$ grep -Eo '^(\\.|[^\\;])*' file
foo\;bar
foo\\

sed 's/\\\(.\)/\1/g'エスケープを削除するには、そのオプションもサポートされている場合は、操作全体をパイプまたは実行します。sedsed-E

$ sed -E 's/^((\\.|[^\\;])*).*/\1/; s/\\(.)/\1/g' file
foo;bar
foo\

または以下を使用してperl

$ perl -lpe 's/^(\\.|[^;])*+\K.*//; s/\\(.)/$1/g' file
foo;bar
foo\

1 ただし、空のgrep -o一致は出力されません。

関連情報