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"

      

+1


source to share


4 answers


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.

0


source


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.

+1


source


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);
}

      

+1


source


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

?

0


source







All Articles