Reputation: 472
This script is incomplete since I will want to do error testing later, but the idea is that ARG is a script and ARG2 is a directory, and ARG should mark all of the files in ARG2. How would I do this in such a way that bash knows the first argument has to be a script and argument 2 is a directory?
ARG=$1
ARG2=$2
CHECK=0
aCount=0
bCount=0
cCount=0
dCount=0
fCount=0
if [ $CHECK -e 0 ]; then
for files in $ARG2; do
if [ sh $1 $2 -eq A]; then
aCount=$((aCount+1))
elif [ sh $1 $2 -eq B];
bCount=$((bCount+1))
elif [ sh $1 $2 -eq C];
cCount=$((cCount+1))
elif [ sh $1 $2 -eq D ];
dCount=$((dCount+1))
else;
fCount=$((fCount+1))
fi
done
fi
echo A: $aCount
echo B: $bCount
echo C: $cCount
echo D: $dCount
echo F: $fCount
Upvotes: 0
Views: 45
Reputation: 15293
@John Kugelman did a great job above. For an alternate take -
declare -A count # count is an array
for file in "$dir"/* # skipping assignments, and $check
do grade=$("$script" "$file") # grab the output as $grade
case $grade in # look up its value
[A-D]) (( count[$grade]++ ));; # use as-is for a-d
*) (( count['F']++ ));; # throw everything else in f
esac
done
for g in A B C D F # then for a-f (known values)
do echo "$g: "${count[$g]} # pull the counts
done
Upvotes: 2
Reputation: 361635
There are a variety of errors you could catch by running your script through shellcheck.net.
Corrections:
To loop over the files in a directory, write for file in dir/*
not for file in dir
. The latter just loops once with $file
set to the string "dir"
, rather than iterating over the contents of the directory dir/
.
[ sh $1 $2 -eq A]
is a jumble of shell constructs. You want to capture the output of the script, so you need $(...)
. You're doing a string check, so you should use ==
not -eq
. Correcting both yields:
[ $(sh $1 $2) == A ]
I'm guessing $2
should be $files
, though. The loop variable, yes?
[ $(sh $1 $files) == A ]
There are other miscellaneous mistakes, such as missing then
s and not always having a space before ]
.
Improvements:
You should quote everything properly to prevent inadvertent word splitting and glob expansion.
[ "$(sh "$1" "$files")" == A ]
Let's replace $1
with $script
and $files
with singular $file
.
[ "$(sh "$script" "$file")" == A ]
If the script has a proper shebang line like #!/bin/bash
at the top then there's no need to explicitly invoke sh
.
[ "$("$script" "$file")" == A ]
That's all great. Now you have something like this:
if [ "$("$script" "$file")" == A ]; then
aCount=$((aCount+1))
elif [ "$("$script" "$file")" == B ]; then
bCount=$((bCount+1))
elif [ "$("$script" "$file")" == C ]; then
cCount=$((cCount+1))
elif [ "$("$script" "$file")" == D ]; then
dCount=$((dCount+1))
else
fCount=$((fCount+1))
fi
Awfully repetitious, no? Let's try a case
statement instead.
case "$("$script" "$file")" in
A) aCount=$((aCount+1));;
B) bCount=$((bCount+1));;
C) cCount=$((cCount+1));;
D) dCount=$((dCount+1));;
*) fCount=$((fCount+1));;
esac
That case statement is still quite complex. Let's break it up to make it easier to parse.
grade=$("$script" "$file")
case $grade in
...
esac
Variable names ought to be lowercase. UPPERCASE names are reserved for the shell, so best not to use those. Change COUNT
to count
.
Let's rename ARG
and ARG2
to script
and dir
, respectively. Meaningful names make everything easier to read.
var=$((var+1))
can be simplified to ((var += 1))
or ((var++))
.
End result:
script=$1
dir=$2
check=0
aCount=0
bCount=0
cCount=0
dCount=0
fCount=0
if ((check == 0)); then
for file in "$dir"/*; do
grade=$("$script" "$file")
case $grade in
A) ((aCount++));;
B) ((bCount++));;
C) ((cCount++));;
D) ((dCount++));;
*) ((fCount++));;
esac
done
fi
echo "A: $aCount"
echo "B: $bCount"
echo "C: $cCount"
echo "D: $dCount"
echo "F: $fCount"
Upvotes: 4