【问题标题】:Pass argument to awk inside do loop在 do 循环中将参数传递给 awk
【发布时间】:2016-07-07 23:06:59
【问题描述】:

我有大量制表符分隔的文本文件,其中包含我在第二列中感兴趣的乐谱:

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" 那样向 awk 传递一个参数,如 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  

我做错了什么?

【问题讨论】:

    标签: linux bash shell awk


    【解决方案1】:

    在您的 shell 脚本中,shellscript 的第一个参数是 $1。您可以将该值分配给 awk 变量,如下所示:

    find . -name 'test_score_*.txt' -type f -exec awk -v a="$1" -F'\t' '$2 < a' {} +
    

    讨论

    • 您的 print0/while 读取循环非常好。但是,find 提供的 -exec 选项可以在没有任何显式循环的情况下运行相同的命令。

    • 可以选择将命令{if ($2 &lt; -7.5) print $0} 简化为条件$2 &lt; -7.5。这是因为条件的默认操作是print $0

    • 请注意,引用 $1$2 彼此完全不相关。因为$1 用双引号括起来,所以shell 会在 awk 命令开始运行之前替换它。 shell 将$1 解释为脚本的第一个参数。因为$2 出现在单引号中,所以shell 不理会它,它由awk 解释。 awk 将其解释为当前记录的第二个字段。

    【讨论】:

      【解决方案2】:

      你的第一个例子:

      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"
      

      http://cfajohnson.com/shell/cus-faq-2.html#Q24

      【讨论】:

        猜你喜欢
        • 2021-06-21
        • 2011-09-27
        • 1970-01-01
        • 2012-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-30
        相关资源
        最近更新 更多