[英]unix - awk unexpected behaviour
我在名为“ findError.sh”的bash文件中具有以下代码:
#!/bin/bash
filename="$1"
formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count
然后,我在命令行上像这样运行它:sh findError.sh test.dat
但这给了我与运行回显命令不同的计数? 这怎么可能?
即回显的$ command是:
awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
但是回显的$ count是:
3
但是,如果我仅在命令行下面(而不是通过脚本)运行这一行,则结果为0:
awk -F"|" '{print $1}' test.dat | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
样本输入文件(test.dat):
sid|storeNo|latitude|longitude
2|1|-28.03720000
9|2
10
jgn352|1|-28.03ERROR720000
9|2|fdERRORkjhn422-405
0000543210|gfERRORdjk39
注意:将SunOS与bash版本4.0.17一起使用
您对格式定界符的引号过于谨慎。
当您键入:
awk -F"|" ...
程序( awk
)看到-F|
作为第一个论点; 外壳会去除双引号。
当你有:
formatindicator="\"|\""
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F$formatindicator ...`
您已在$formatindicator
保留了双引号,因此awk
看到-F"|"
作为分隔符,并使用双引号作为分隔符。
采用:
formatindicator="|"
echo "$formatindicator"
formatarg="\$1"
echo "$formatarg"
count=`awk -F"$formatindicator" ...`
区别在于外壳程序将-F"$formatindicator"
引号引起来,但是当$formatindicator
本身包含双引号时,shell不会这样做。
(注:经过编辑以保留反引号,而不是(a)首选的$(...)
表示法,并且在该答案的第一版中使用了(b)。 $(...)
表示法无法识别我相信,SunOS /bin/sh
是用来执行脚本的bash
和ksh
识别$(...)
表示法,但是在Solaris 10(SunOS)上可以使用基本的Bourne shell /bin/sh
。 5.10)和更早的版本(我还没有接触过Solaris 11)无法识别$(...)
。)
我注意到,可以使用perl
, awk
或grep
中的任何一个自行查找错误行的数量,因此,将awk
的三元组通过管道传输到perl
传输到wc
并不是很有效。
awk -F"|" '$1 ~ /ERROR/ { count++ } END { print count }' $filename
grep -c ERROR $filename # simple
grep -c '^[^|]*ERROR[^|]*|' $filename # accurate
perl -anF"|" -e '$count++ if $F[0] =~ m/ERROR/; END { print "$count\n"; }' $filename
是Perl,所以是TMTOWTDI ; 选择...
在评论中,我们对如何解释脚本的各个部分感到担忧。
formatindicator="|"
formatarg="\$1"
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
让我们简化为(使用我的主要答案的一部分):
count=`awk -F"$formatindicator" '{print $formatarg}' $filename`
目的是通过-F
选项在命令行上指定定界符(成功完成)。 我期望的问题是“为什么$formatarg
会在单引号内扩展?”。 答案是“是吗?”。 我想不是。 因此,发生的是awk
正在查看脚本{print $formatarg}
。 由于formatarg
没有分配任何值,所以它等效于0,因此脚本将输出$0
,这是整个输入行。 如果Perl在行中的任何地方匹配ERROR,Perl都会很高兴地回显该行,并且wc
不在乎行中的内容,因此结果与预期的差不多。 唯一的差异是$filename
中的行在第一个以竖线分隔的字段之外的地方包含ERROR。 脚本会在不应该计数的位置进行计数。
问题在于在awk
使用外部变量。 如果希望在awk
使用外部变量,请使用-v
选项和variable name
在awk
一线式中定义一个变量,然后将其分配给external variable
。 所以
该行-
count=`awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
应该 -
count=`awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
更新:
如评论中所述, $formatarg
包含值$1
。 您需要做的只是存储1
,然后将其传递为-
count=`awk -v fi=$formatindicator -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' "$1" | perl -ane '{ if(m/ERROR/) { print } }' | wc -l
[jaypal:~/Temp] echo $formatindicator
|
[jaypal:~/Temp] echo $formatarg
1
[jaypal:~/Temp] awk -v fi="$formatindicator" -v fa="$formatarg" 'BEGIN {FS=fi}{print $fa}' data.file
sid
2
9
10
jgn352
9
0000543210
脚本:
#!/bin/bash
filename="$1"
formatindicator="|"
echo "$formatindicator"
formatarg="1"
echo "$formatarg"
count=`awk -v fa="$formatarg" -v fi="$formatindicator" 'BEGIN{FS=fi}{print $fa}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l `
command="awk -F$formatindicator '{print $formatarg}' $filename | perl -ane '{ if(m/ERROR/) { print } }' | wc -l"
echo $command
echo $count
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.