Script - rereading arguments
When I put the script argument: hi [123] .txt, it will do exactly what I want. But if I specify a wildcard (hi * .txt) it will reread some files.
I was wondering how to modify this script to fix this stupid problem:
#!/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"
source to share
On error, exit with non-zero status. Also on error, report bugs with standard error rather than standard release, although that might be a little more for you.
echo "$0: file $FILE not readable" 1>&2
1 is theoretically unnecessary (although I remember shell implementation issues in Windows if it was omitted). Repeating the script name sketch ' $0
' at the beginning of the error message is also a good idea - it makes it easier to track down errors later when your script is being used in other contexts.
I believe this one-liner Perl does the job you do.
perl -na -F: -e '$sum += $F[1] if m/^Total:/; END { print $sum; }' "$@"
I understand that you are learning shell programming, but one of the important things with shell programming is knowing which programs to use.
source to share
I don't know what's wrong with it, but one little point I noticed:
Change for FILE in $@
to for FILE in "$@"
. Because if the files have inline spaces, you are now on the safe path. It will expand to "$1" "$2" ...
, then instead of $1 $2 ...
(and note that you are using $ FILE, also remember ""
it).
And as others say, you don't need to initialize FILE
before you introduce the loop. It will be automatically set to each of the extended positional parameter file names in the for loop.
However, I would go with an awk script like this:
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
Note that if a file contains multiple "Count" lines, you would say that you are reading more files than you actually read if you rely on count
to tell you the number of files read.
source to share
This seems like overkill:
FILE="$1" #FILE specification is now $1 Specification..
for FILE in $@
...
The original assignment will be quickly overwritten.
All in all, it looks like a task more suited to a string processing language like awk or perl.
Consider something along the lines of this awk script:
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);
}
source to share
How about this solution:
for FILE in `/bin/ls $@`
do
. . .
This will effectively eliminate duplicates because it /bin/ls hi1.txt hi1.txt hi1.txt
only has to show hi1.txt
once.
Though I'm not sure why it is re-reading the files. The lookup extension should only include one file at a time. Do you have mapped files hi*.txt
that are links to mapped files hi[123].txt
?
source to share