我有大量以制表符分隔的文本文件,其中包含我在第二栏中感兴趣的分数:
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
如果我尝试将参数传递给awk,如check_scores_2.sh "-7.5"
check_score_2.sh
所示,那将返回两个文件中的所有条目。
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
我做错了什么?
答案 0 :(得分:3)
在shell脚本中,shellscript的第一个参数以$1
形式提供。您可以将该值分配给awk变量,如下所示:
find . -name 'test_score_*.txt' -type f -exec awk -v a="$1" -F'\t' '$2 < a' {} +
你的print0 / while读取循环非常好。但是,-exec
提供的find
选项可以在没有任何显式循环的情况下运行相同的命令。
可以选择将命令{if ($2 < -7.5) print $0}
简化为条件$2 < -7.5
。这是因为条件的默认操作是print $0
。
请注意,引用$1
和$2
完全无关。因为$1
是双引号,所以在 awk命令开始运行之前,shell会替换它。 shell将$1
解释为脚本的第一个参数。因为$2
出现在单引号中,所以shell将其单独保留,并由awk解释。 Awk将其解释为其当前记录的第二个字段。
答案 1 :(得分:0)
你的第一个例子:
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"