我有一个包含以下信息的文本文件:
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.