是否可以编写一个脚本来读取包含数字的文件(每行一个)并写入其最大值,最小值和总和。如果文件为空,它将打印一条适当的消息。文件名将作为脚本的参数给出。我要创建以下脚本,但是有2个错误:
./4.3: line 20: syntax error near unexpected token `done'
./4.3: line 20: `done echo "Max: $max" '
是否可以添加多个文件作为参数?
lines=`cat "$1" | wc -l`
if [ $lines -eq 0 ];
then echo "File $1 is empty!"
exit fi min=`cat "$1" | head -n 1`
max=$min sum=0
while [ $lines -gt 0 ];
do num=`cat "$1" |
tail -n $lines`
if [ $num -gt $max ];
then max=$num
elif [ $num -lt $min ];
then min=$num fiS
sum=$[ $sum + $num] lines=$[ $lines - 1 ]
done echo "Max: $max"
echo "Min: number $min"
echo "Sum: $sum"
答案 0 :(得分:2)
在这里相当吸引人地使用GNU datamash:
read sum min max < <( datamash sum 1 min 1 max 1 < "$1" )
[[ -z $sum ]] && echo "file is empty"
echo "sum=$sum; min=$min; max=$max"
或者,排序并awk:
sort -n "$1" | awk '
NR == 1 { min = $1 }
{ sum += $1 }
END {
if (NR == 0) {
print "file is empty"
} else {
print "min=" min
print "max=" $1
print "sum=" sum
}
}
'
答案 1 :(得分:2)
在这里,我会尽可能地保留您的初衷,以解决您的原始尝试:
#!/usr/bin/env bash
lines=$(wc -l "$1")
if [ "$lines" -eq 0 ]; then
echo "File $1 is empty!"
exit
fi
min=$(head -n 1 "$1")
max=$min
sum=0
while [ "$lines" -gt 0 ]; do
num=$(tail -n "$lines" "$1")
if [ "$num" -gt "$max" ]; then
max=$num
elif [ "$num" -lt "$min" ]; then
min=$num
fi
sum=$(( sum + num ))
lines=$(( lines - 1 ))
done
echo "Max: $max"
echo "Min: number $min"
echo "Sum: $sum"
交易突破者缺少换行符(不能在没有exit fi
的一行上使用;
);其他更改也是好的做法(引用扩展名,cat
的无用使用),但不会阻止脚本工作;其他则是装饰性的(缩进,没有反引号)。
不过,整体方法是一个庞大的反模式:您要读取要处理的每一行的整个文件。
这是我要怎么做:
#!/usr/bin/env bash
for fname in "$@"; do
[[ -s $fname ]] || { echo "file $fname is empty" >&2; continue; }
IFS= read -r min < "$fname"
max=$min
sum=0
while IFS= read -r num; do
(( sum += num ))
(( max = num > max ? num : max ))
(( min = num < min ? num : min ))
done < "$fname"
printf '%s\n' "$fname:" " min: $min" " max: $max" " sum: $sum"
done
这使用正确的方法来循环输入文件,并在算术上下文中利用三元运算符。
最外面的for
循环遍历所有参数。
答案 2 :(得分:0)
您可以在shell脚本中的while循环中完成全部操作。这是bash版本:
s=0
while read x; do
if [ ! $mi ]; then
mi=$x
elif [ $mi -gt $x ]; then
mi=$x
fi
if [ ! $ma ]; then
ma=$x
elif [ $ma -lt $x ]; then
ma=$x
fi
s=$((s+x))
done
if [ ! $ma ]; then
echo "File is empty."
else
echo "s=$s, mi=$mi, ma=$ma"
fi
将该脚本保存到文件中,然后可以使用管道将任意数量的输入文件发送到其中,就像这样(假设脚本称为“ mysum”):
cat file1 file2 file3 | mysum
或单个文件
mysum < file1
(请确保脚本是可执行文件,并且在$ PATH上,否则,对当前目录中的脚本使用“ ./mysum”;如果不可执行,则使用“ bash mysum”。)
该脚本假定每行数字为1,并且该行没有其他内容。如果输入为空,则会显示一条消息。
它如何工作? “ read x”将逐行从stdin输入。如果文件为空,则while循环将永远不会运行,因此不会设置变量mi和ma。因此,我们最后使用它来触发适当的消息。否则,循环将首先检查mi和ma变量是否存在。如果不是,则使用第一个x进行初始化。否则,检查下一个x是否需要更新到目前为止找到的mi和ma。
请注意,此技巧可确保您输入任意数字序列。否则,您必须使用绝对太大的东西来初始化mi,而必须使用绝对太小的东西来初始化-直到您遇到一个奇怪的数字列表时,它才起作用。
请进一步注意,这仅适用于整数。如果您需要使用浮子,则需要使用除Shell之外的其他工具,例如啊!
只是为了好玩,这是awk版本,单行,按原样或在脚本中使用,它也适用于浮点数:
cat file1 file2 file3 | awk 'BEGIN{s=0}; {s+=$1; if(length(mi)==0)mi=$1; if(length(ma)==0)ma=$1; if(mi>$1)mi=$1; if(ma<$1)ma=$1} END{print s, mi, ma}'
或一个文件:
awk 'BEGIN{s=0}; {s+=$1; if(length(mi)==0)mi=$1; if(length(ma)==0)ma=$1; if(mi>$1)mi=$1; if(ma<$1)ma=$1} END{print s, mi, ma}' < file1
缺点:如果没有给出有关空文件的错误消息。
答案 3 :(得分:0)
一个脚本,该文件读取包含数字的文件(每行一个)并写入其最大值,最小值和总和
使用sort
的Bash解决方案:
<file sort -n | {
read -r sum
echo "Min is $sum"
while read -r num; do
sum=$((sum+num));
done
echo "Max is $num"
echo "Sum is $sum"
}
让我们通过使用tee
,tr
进行一些智能解析并使用bc
进行计算来加快速度,如果我们不介意使用stderr进行输出。但是我们可以做些fifo并同步tee输出。无论如何:
{
<file sort -n |
tee >(echo "Min is $(head -n1)" >&2) >(echo "Max is $(tail -n1)" >&2) |
tr '\n' '+';
echo 0;
} | bc | sed 's/^/Sum is /'
总是有datamash
。以下Willl输出3个数字,即和,最小和最大:
<file datamash sum 1 min 1 max 1
答案 4 :(得分:0)
您可以尝试使用shell循环和dc
while [ $# -gt 0 ] ; do
dc -f - -e '
['"$1"' is empty]sa
[la p q ]sZ
z 0 =Z
# if file is empty
dd sb sc
# populate max and min with the first value
[d sb]sY
[d lb <Y ]sM
# if max keep it
[d sc]sX
[d lc >X ]sN
# if min keep it
[lM x lN x ld + sd z 0 <B]sB
lB x
# on each line look for max, min and keep the sum
[max for '"$1"' = ] n lb p
[min for '"$1"' = ] n lc p
[sum for '"$1"' = ] n ld p
# print summary at end of each file
' <"$1"
shift
done