我有大量的制表符分隔的文本文件,其中包含我在第二列中感兴趣的分数:
test_score_1.txt
Title FRED Chemgauss4 File 24937 -6.111582 A 24972 -7.644171 A 26246 -8.551361 A 21453 -7.291059 A
test_score_2.txt
Title FRED Chemgauss4 File 14721 -7.322331 B 27280 -6.229842 B 21451 -8.407396 B 10035 -7.482369 B 10037 -7.706176 B
我想检查是否有比我定义的数字更小的分数。
以下代码在脚本中定义了我的分数,并且工作如下:
check_score_1
#!/bin/bash find . -name 'test_score_*.txt' -type f -print0 | while read -r -d $'\0' x; do awk '{FS = "\t" ; if ($2 < -7.5) print $0}' "$x" done
如果我试图像check_scores_2.sh "-7.5"
那样将一个parameter passing给awk,如check_scores_2.sh "-7.5"
中所示,则返回两个文件中的所有条目。
check_scores_2.sh
#!/bin/bash find . -name 'test_score_*.txt' -type f -print0 | while read -r -d $'\0' x; do awk '{FS = "\t" ; if ($2 < ARGV[1]) print $0}' "$x" done
最后, check_scores_3.sh
显示我实际上没有从我的命令行传递任何参数。
check_scores_3.sh
#!/bin/bash find . -name 'test_score_*.txt' -type f -print0 | while read -r -d $'\0' x; do awk '{print ARGV[0] "\t" ARGV[1] "\t" ARGV[2]}' "$x" done
$ ./check_score_3.sh "-7.5"
给出以下输出:
awk ./test_score_1.txt awk ./test_score_1.txt awk ./test_score_1.txt awk ./test_score_1.txt awk ./test_score_1.txt awk ./test_score_2.txt awk ./test_score_2.txt awk ./test_score_2.txt awk ./test_score_2.txt awk ./test_score_2.txt awk ./test_score_2.txt
我究竟做错了什么?
在shell脚本中,shell脚本的第一个参数是$1
。 您可以将该值分配给awk变量,如下所示:
find . -name 'test_score_*.txt' -type f -exec awk -va="$1" -F'\t' '$2 < a' {} +
你的print0 / while循环是非常好的。 find
提供的-exec
选项使得运行相同的命令成为可能,而不需要任何明确的循环。
命令{if ($2 < -7.5) print $0}
可以被简化为条件$2 < -7.5
。 这是因为条件的默认操作是print $0
。
请注意,引用$1
和$2
是完全不相关的。 由于$1
是双引号,所以在 awk命令开始运行之前 ,shell会替换它。 shell将$1
解释$1
脚本的第一个参数。 由于$2
出现在单引号中,因此shell将其独立并由awk解释。 Awk将其解释为其当前记录的第二个字段。
你的第一个例子:
awk '{FS = "\t" ; if ($2 < -7.5) print $0}' "$x"
只有一个幸福的巧合,设置FS实际上对你的具体情况没有任何影响。 否则,输入文件的第一行就会失败,因为你没有设置FS,直到第一行被读取并被分割成字段。 你的意思是:
awk 'BEGIN{FS = "\t"} {if ($2 < -7.5) print $0}' "$x"
这可以更正确地写成:
awk -F'\t' '$2 < -7.5' "$x"
对于第二种情况,你只是没有通过争论,就像你已经意识到的那样。 所有你需要做的是:
awk -F'\t' -v max="$1" '$2 < max' "$x"