【问题标题】:Error in Echo of awk command piped to wc -l通过管道传送到 wc -l 的 awk 命令的 Echo 错误
【发布时间】:2014-01-23 23:58:51
【问题描述】:

我有数百个文件包含与此类似的行:

>34764998   Halalkalicoccus_jeotgali_B3   -132.6938   Halalkalicoccus   0.528  Halobacteriaceae  0.638 Halobacteriales   0.648 Halobacteria   0.706 Euryarchaeota  0.850 

我有兴趣计算第 5 列中小于 0.1、...0.95 的项目数。我编写了一个 bash 脚本,它调用一个 AWK 命令来查看列值,然后将其通过管道传输到 wc -l(见下文)。但是,我的 $、' 和括号排列不正确。谁能告诉我我做错了什么?这可能不是最有效的方法,所以我欢迎提出建议,但我确实想知道我列出的代码做错了什么。

for fileName in 4440319.3_genus.txt 4440372.3_genus.txt 4440373.3_genus.txt 4440378.3_genus.txt 4440379.3_genus.txt 4440380.3_genus.txt 4440381.3_genus.txt
do
   echo $fileName
   for number in 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.95
   do  
      #NUM={awk '$5 < '$number' {print $5}' $filename | wc -l}
      NUM={awk '$5 < $number {print $5}' $filename | wc -l} 
      #NUM=${awk '$5 < '$number' {print $5}' $filename | wc -l}
      #NUM=${awk '$5 < $number {print $5}' $filename | wc -l}
      echo $NUM
   done
done
exit 0

所有变体都会产生无效的选项错误,具体取决于未注释的行。

非常感谢。

【问题讨论】:

    标签: bash awk pipe


    【解决方案1】:

    你不需要wc -l 管道,甚至不需要文件名的for循环,试试这个:

    awk -v n=0.95 '$5<n{a++}END{print a}' *_genus.txt
    

    【讨论】:

    • @nickie 有一个可行的解决方案,但我对你的解决方案很好奇,我正在运行它,我收到一个值而不是 40 个值。我错过了什么?
    • 你删除了wc -l吗?
    • @cer 答案中的行将打印所有 *_gen...txt 文件中的总行数 $5&lt;0.95 如果你想获得不同 n 的行数,比如 0.1、0.2 .... 你可以使用你的 shell 脚本,你也可以构建一个 awk 数组。你没有给出预期的输出,所以我没有给出更多的代码。您的要求会有问题。
    • @Kent 可能会建议您将整个 shell 脚本替换为:for number in 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.95; do awk -v n=$number 'BEGIN{a=0} $5&lt;n {a++} END {print a}' *_genus.txt; done。这应该可以,但它会总结所有文件的计数器。注意BEGIN初始化a;如果您希望出现零,这是必需的。
    • @nickie 是的,这就是我的意思。 awk 数组也可能更好。此外,如果他想获得每个文件的计数,awk 也可以处理它,我们可以使用内置的 Var: FILENAME 和参数 idx 等。但我不知道确切的要求。既然你的解决方案已经解决了他的问题,那很好。附言我说 awk 数组更好,因为假设有 500 个文件,我们要计算 10 个范围,通过两个循环,我们必须为每个文件解析 10 次。使用 awk 数组,我们可以每个文件处理一次。
    【解决方案2】:

    假设您使用的是shbash,我会这样做:

    NUM=`awk -v x=$number '$5 < x {print $5}' $fileName | wc -l`
    

    一些解释为什么这有效而你的尝试不起作用:

    1. 您需要执行管道并将其输出存储在变量NUM中。这就是为什么你需要在管道周围加上反引号。

    2. 您的$number 是一个shell 变量。 Shell 变量扩展不会发生在单引号内,因此 awk 脚​​本中的 $number 没有机会被您想要的数字替换。为了解决这个问题,您可以使用双引号将数字嵌入到正确的位置(这会导致一些麻烦,因为您不想被 shell 扩展的 awk 脚本中的其他美元符号),或者您可以使用外部初始化的awk 变量。这就是 -v 参数的作用。

    3. 最后但同样重要的是,您需要修复 filename 中的小写“N”。

    【讨论】:

    • 啊哈!是的,除了 -v 和 x= 的东西,我总是忘记它是 `,而不是 '。非常感谢@nickie。完美运行。
    • 还有@nickie,非常感谢您的解释。
    【解决方案3】:

    这里我给出完整的脚本:

    for fileName in 4440319.3_genus.txt 4440372.3_genus.txt 4440373.3_genus.txt 4440378.3_genus.txt 4440379.3_genus.txt 4440380.3_genus.txt 4440381.3_genus.txt
    do
       echo $fileName
       for number in 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.95
       do  
          NUM={awk -v n=$number '$5<n{a++}END{print a}'} 
          echo "$NUM records is less than $number"
       done
    done
    exit 0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-12
      • 1970-01-01
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 2018-08-18
      • 2020-05-10
      • 1970-01-01
      相关资源
      最近更新 更多