当我为脚本提供参数时:hi [123] .txt它将完全符合我的要求。 但是如果我指定通配符(hi * .txt),它将重新读取一些文件。
我想知道如何修改这个脚本来解决这个愚蠢的问题:
#!/bin/sh
count="0"
total="0"
FILE="$1" #FILE specification is now $1 Specification..
for FILE in $@
do
#if the file is not readable then say so
if [ ! -r $FILE ];
then
echo "File: $FILE not readable"
exit 0
fi
# Start processing readable files
while read line
do
if [[ "$line" =~ ^Total ]];
then
tmp=$(echo $line | cut -d':' -f2)
total=$(expr $total + $tmp)
echo "$FILE (s) have a total of:$tmp "
count=$(expr $count + 1)
fi
done < $FILE
done
echo " Total is: $total"
echo " Number of files read is:$count"
答案 0 :(得分:1)
我不知道它有什么问题,但我注意到了一点:
将for FILE in $@
更改为for FILE in "$@"
。因为如果文件有嵌入空格,那么现在就是安全的。它会扩展为"$1" "$2" ...
,而不是$1 $2 ...
(并注意到你使用$ FILE的所有地方都要记得""
)。
而其他人说,在进入循环之前,您不需要初始化FILE
。它将自动设置为for循环中展开的位置参数的每个文件名。
但是,我会使用这样的awk脚本:
awk -F: '
/^Total/ {
total += $2
# count++ not needed. see below
print FILENAME "(s) have a total of: " $2
}
END {
print "Total is: " total
print "Number of files read is: " (ARGC-1)
}' foo*.txt
请注意,当一个文件包含多个“^ Count”行时,如果依靠count
告诉您读取的文件数,您确实会说您读取的文件数量超过实际读取的数量。
答案 1 :(得分:1)
这似乎是多余的:
FILE="$1" #FILE specification is now $1 Specification..
for FILE in $@
...
初始分配会立即被覆盖。
总的来说,这似乎是一个更适合awk或perl等行处理语言的任务。
考虑一下这个awk脚本的内容:
BEGIN{
TOTAL=0;
COUNT=0;
FS=':';
}
/^Total/{
TOTAL += $2;
COUNT++;
printf("File '%s' has a total of %i",FILENAME,TOTAL);
}
END{
printf("Total is %i",TOTAL);
printf("Number of files read is%i",COUNT);
}
答案 2 :(得分:0)
这个解决方案怎么样:
for FILE in `/bin/ls $@`
do
. . .
这样可以有效地消除重复,因为/bin/ls hi1.txt hi1.txt hi1.txt
只应显示hi1.txt
一次。
虽然我不确定为什么它会重新读取文件。通配符扩展应该只包含每个文件一次。您是否有hi*.txt
匹配的文件是指向hi[123].txt
匹配的文件的链接?
答案 3 :(得分:0)
出错时,退出非零状态。同样出错时,将错误报告给标准错误,而不是标准输出 - 尽管这对您来说可能有点先进。
echo "$0: file $FILE not readable" 1>&2
1在理论上是不必要的(虽然我记得在Windows上有一个shell实现的问题,如果它被省略)。在错误消息的开头回应脚本名称“$0
”也是一个好主意 - 当您的脚本在其他上下文中使用时,它会使错误跟踪更容易。
我相信Perl one-liner能胜任你所追求的工作。
perl -na -F: -e '$sum += $F[1] if m/^Total:/; END { print $sum; }' "$@"
我知道您正在学习shell编程,但shell编程的一个重要事项是知道要使用哪些程序。