shell 脚本中带有循环的管道

shell 脚本中带有循环的管道

我有一个包含以下信息的文本文件:

Game Copies_Sold(M) Release_date Genre   
God_of_War 19 20/04/2018 Action-Adventure 
Uncharted_4 16 10/05/2016 Action-adventure 
Spider-Man 13 07/09/2018 Action-adventure  
The_Witcher_3 10 18/05/2015 Action_role-playing

我需要对第二列的数字求和,所以我写了这个脚本:

#!/bin/bash                                           
file=$1                                                   
s=0                                                      
tail -n +2 $file |cut -f 2 |                                
{ while read line                                          
do                                                      
s=$(( $s+$line ))                                        
done <$file }                                            
echo $s

但显然我做错了什么。这里要做什么?谢谢你!

答案1

应该是这样的:

#! /bin/sh -
file=${1?}
awk 'NR >= 2 {sum += $2}; END {print sum+0}' < "$file"

您的方法存在问题:

  • 您不检查是否至少有一个参数传递给您的脚本(此处粗略地用 来解决${1?})。
  • 周围缺少引号$file
  • 缺少--fortail来标记选项的结尾(挑剔:和相同-在舍邦
  • 默认分隔符cut是 TAB,而您的输入看起来是空格分隔的。默认awk分隔符是任意数量的空格(包括空格和制表符)。
  • 您正在通过管道传输到循环,但也从 重定向该循环的输入$file
  • 之前缺少;或换行}
  • 缺少-r选项read
  • 在 bash 中,管道最右侧的组件也在子 shell 中运行(除非lastpipe启用该选项),因此$s管道返回后对变量的更改将会丢失。
  • 但首先您正在使用 shell 循环来处理文本,这通常是不好的做法,效率低且难以正确执行
  • 这里的情况和你一样更糟对外部输入使用 shell 算术,这会在 bash 中引入命令注入漏洞
  • 您的脚本中没有任何特定于 bash 的内容,因此您可以通过更改 shebang 以使用系统的sh.

其中一些错误会被外壳检查(也可以作为独立软件安装在您的系统上)。

在这里,它给出:

$ shellcheck myscript
 
Line 4:
tail -n +2 $file |cut -f 2 |                                
           ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
tail -n +2 "$file" |cut -f 2 |                                
 
Line 5:
{ while read line                                          
        ^-- SC2162 (info): read without -r will mangle backslashes.
 
Line 7:
s=$(( $s+$line ))                                        
^-- SC2030 (info): Modification of s is local (to subshell caused by pipeline).
      ^-- SC2004 (style): $/${} is unnecessary on arithmetic variables.
         ^-- SC2004 (style): $/${} is unnecessary on arithmetic variables.
 
Line 8:
done <$file }                                            
      ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
done <"$file" }                                            
 
Line 9:
echo $s
     ^-- SC2031 (info): s was modified in a subshell. That change might be lost.

相关内容