Unix コマンドでエスケープされた区切り文字を回避するにはどうすればよいですか?

Unix コマンドでエスケープされた区切り文字を回避するにはどうすればよいですか?

チルダ (~) で区切られたフィールドの合計を取得する必要があります。問題は、データにも区切り文字がエスケープされていることです。

1~CEO~ashok\~kumar~1000

上記の 3 番目のフィールドを見ると、回避したい区切り文字がエスケープされています。これに対応していない以下のコマンドを実行しています。

$ cat test.out|awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'

データを次のように想定しますtest.out:

1~CEO~ashok\~kumar~1000
2~CFO~Ranjan~2000
3~CEO~kumar~1000

したがって、出力は 4000 になるはずです。しかし、現在、私のコマンドでは 3000 しか得られません。

答え1

で処理する前に、エスケープされた区切り文字を別のものに変更するだけですawk。これは次のように実行できますsed

$ cat test.out| sed 's/\\~/=/g' | \
    awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'
4000

そして、よくあることですが、 はcat必要ありません。

$ sed 's/\\~/=/g' test.out | awk -F'~' 'BEGIN {sum=0} {sum+=$4} END{print sum}'

答え2

を使用しない代替手段を次に示しますawk

$ sed 's/\\~/=/g' test.out | cut -d"~" -f4 | paste -sd+ | bc
4000

上記では、3 列目のsedエスケープされたチルダを交換するためにを使用しています。その後、 を使用して4 列目の数字を選択し、プラス記号 ( ) で区切られるように再構築します。\~cut+

$ sed 's/\\~/=/g' test.out | cut -d"~" -f4 | paste -sd+
1000+2000+1000

この文字列はバイナリ計算機に渡され、bc合計が計算されます。

答え3

エスケープ処理を扱う一般的な方法は、perlまたは PCRE とその代替正規表現演算子を非バックトラック演算子と組み合わせて使用​​することです。ここでは GNU を使用しますgrep:

grep -Po '(?>(?:\\.|.)*?~){3}\K(?:\\.|[^~])*' << \EOF
1~CEO~ashok\~kumar~1000
2~CFO~Ranjan~2000
3~CEO~kumar~1000
4~field2~field3\\~10000~field5-note-the-escaped-backslash-not-tilde
5~a\~b\~c\~no-4th-field-here
EOF

これにより、次のようになります。

1000
2000
1000
10000

(通常の で合計できますawk '{s+=$0};END{print s}')。

GNU ではsed、次のように実行することもできます。

sed -rn 's/((\\.|[^\~])*~){3}((\\.|[^~])*).*/\3/p'

GNU では、 を使用して、フィールドをエスケープされた文字またはチルダやバックスラッシュ以外の文字のシーケンスとして定義awkできます。FPAT

awk -v FPAT='(\\\\.|[^\\\\~])*' '{print $4}'

答え4

これは awk では少し扱いに​​くいです (ソースを前処理して区切り文字を変更できる場合を除きますが、そのためには入力に出現できない別の文字または文字シーケンスを知っている必要があります)。 1 つの方法は、行全体を読み取り、行を調整して改行を区切り文字として使用することです (改行は行に出現できない唯一のものです)。

awk 'BEGIN {FS="\n"}
{
    gsub("~", "\n");
    gsub("\\\n", "~");
    gsub("\\\\", "\\");
    $0 = $0;
    print $4;
}'

関連情報