我需要计算以波形符 (~) 分隔的字段的总和。我遇到的问题是我的数据也有分隔符转义。
例子
1~CEO~ashok\~kumar~1000
正如我们在上面的第三个字段中看到的,我们已经转义了我想避免的分隔符。我正在运行以下命令,但它无法处理此问题。
$ 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
上面的代码用于sed
交换\~
第三列中转义的波形符。然后我们可以使用cut
选择第四列数字,然后重建它们,以便它们之间用加号(+
)分隔。
$ sed 's/\\~/=/g' test.out | cut -d"~" -f4 | paste -sd+
1000+2000+1000
然后将该字符串提供给二进制计算器,bc
对它们进行求和。
答案3
为了处理转义,一般的方法是使用perl
or 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 中有点笨拙(除非您可以预处理源代码来更改分隔符,但这需要知道另一个不能出现在输入中的字符或字符序列)。您可以做的一件事是读取整行,然后修改该行以获取换行符作为分隔符(换行符是不可能出现在一行中的一件事)。
awk 'BEGIN {FS="\n"}
{
gsub("~", "\n");
gsub("\\\n", "~");
gsub("\\\\", "\\");
$0 = $0;
print $4;
}'