How can I get my bash script to work?

2019-09-20 19:02发布

问题:

My bash script doesn't work the way I want it to:

#!/bin/bash

total="0"
count="0"
#FILE="$1" This is the easier way
for FILE in $*
do
    # Start processing all processable files
    while read line
    do
        if [[ "$line" =~ ^Total ]];
        then
            tmp=$(echo $line | cut -d':' -f2)
            count=$(expr $count + 1)
            total=$(expr $total + $tmp)
        fi     
    done < $FILE
done
echo "The Total Is: $total"
echo "$FILE"

Is there another way to modify this script so that it reads arguments into $1 instead of $FILE? I've tried using a while loop:

while [ $1 != "" ]
  do ....
done

Also when I implement that the code repeats itself. Is there a way to fix that as well?

Another problem that I'm having is that when I have multiple files hi*.txt it gives me duplicates. Why? I have files like hi1.txt hi1.txt~ but the tilde file is of 0 bytes, so my script shouldn't be finding anything.


What i have is fine, but could be improved. I appreciate your awk suggestions but its currently beyond my level as a unix programmer.

Strager: The files that my text editor generates automatically contain nothing..it is of 0 bytes..But yeah i went ahead and deleted them just to be sure. But no my script is in fact reading everything twice. I suppose its looping again when it really shouldnt. I've tried to silence that action with the exit commands..But wasnt successful.

while [ "$1" != "" ]; do
    # Code here

    # Next argument
    shift
done

This code is pretty sweet, but I'm specifying all the possible commands at one time. Example: hi[145].txt If supplied would read all three files at once. Suppose the user enters hi*.txt; I then get all my hi files read twice and then added again.

How can I code it so that it reads my files (just once) upon specification of hi*.txt? I really think that this is because of not having $1.

回答1:

It looks like you are trying to add up the totals from the lines labelled 'Total:' in the files provided. It is always a good idea to state what you're trying to do - as well as how you're trying to do it (see How to Ask Questions the Smart Way).

If so, then you're doing in about as complicated a way as I can see. What was wrong with:

grep '^Total:' "$@" |
cut -d: -f2 |
awk '{sum += $1}
     END { print sum }'

This doesn't print out "The total is" etc; and it is not clear why you echo $FILE at the end of your version.

You can use Perl or any other suitable program in place of awk; you could do the whole job in Perl or Python - indeed, the cut work could be done by awk:

grep "^Total:" "$@" |
awk -F: '{sum += $2}
         END { print sum }'

Taken still further, the whole job could be done by awk:

awk -F: '$1 ~ /^Total/ { sum += $2 }
         END { print sum }' "$@"

The code in Perl wouldn't be much harder and the result might be quicker:

perl -na -F: -e '$sum += $F[1] if m/^Total:/; END { print $sum; }' "$@"

When iterating over the file name arguments provided in a shell script, you should use '"$@"' in place of '$*' as the latter notation does not preserve spaces in file names.

Your comment about '$1' is confusing to me. You could be asking to read from the file whose name is in $1 on each iteration; that is done using:

while [ $# -gt 0 ]
do
     ...process $1...
     shift
done

HTH!



回答2:

If you define a function, it'll receive the argument as $1. Why is $1 more valuable to you than $FILE, though?

#!/bin/sh

process() {
    echo "doing something with $1"
}

for i in "$@" # Note use of "$@" to not break on filenames with whitespace
do
    process "$i"
done


回答3:

while [ "$1" != "" ]; do
    # Code here

    # Next argument
    shift
done

On your problem with tilde files ... those are temporary files created by your text editor. Delete them if you don't want them to be matched by your glob expression (wildcard). Otherwise, filter them in your script (not recommended).



标签: bash unix shell