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置き換えます。\~次に、cutを使用して数字の4番目の列を選択し、プラス記号()で区切るように再設定できます+

$ 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;
}'

関連情報