我在名为'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
但它给我一个不同的计数而不是运行被回显的命令?这怎么可能?
即 回显的$命令是:
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一起使用
答案 0 :(得分:4)
您对格式分隔符周围的引号过于谨慎。
键入时:
awk -F"|" ...
程序(awk
)将-F|
视为其第一个参数; shell剥去双引号。
当你有:
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" ...`
不同之处在于shell将引号从-F"$formatindicator"
中删除,但在$formatindicator
本身包含双引号时不会这样做。
(注意:编辑后保留后引号而不是{(1)}符号,这是(a)首选,(b)在此答案的第一个版本中使用。$(...)
表示法不是由SunOS $(...)
识别,我相信它被用来执行脚本。/bin/sh
和bash
都识别ksh
符号,但基本的Bourne shell,{ {1}},在Solaris 10(SunOS 5.10)和更早版本(我没有在Solaris 11上工作)无法识别$(...)
。)
我注意到/bin/sh
,$(...)
或perl
中的任何一个都可用于查找错误行的计数,因此awk
管道的三元组用grep
管道传输到awk
的效率不高。
perl
这是Perl,所以TMTOWTDI;接受你的选择...
在评论中,我们担心如何解释脚本的各个部分。
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
目的是通过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
未分配任何值,因此它等于0,因此脚本会打印{print $formatarg}
,这是整个输入行。如果它在线上的任何地方匹配ERROR,Perl非常乐意回应该行,并且formatarg
不关心行中的内容,因此结果大致与预期相符。只有当$0
中的行包含ERROR而不是第一个以管道分隔的字段时,才会出现差异。这将由脚本计算在哪里不应该。
答案 1 :(得分:1)
问题在于使用awk
中的外部变量。如果您希望在awk
中使用外部变量,请使用awk
选项和-v
在variable name
单行中定义变量,并将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