开发者

Why doesn't my variable seem to increment in my bash while loop?

I am fairly new to bash scripting. I can't seem to get the correct value of my counting variables to display at the end of of a while loop in my bash script.

Background: I have a fairly simple task: I would like to pass a text file containing a list of file paths to a bash script, have it check for the existence of those files, and count the number of existing/missing files. I got most of the script to work, except for the counting part.

N=0
correct=0
incorrect=0
cat $1 | while read filename ; do
    N=$((N+1))
    echo "$N"

    if ! [ -f $filename ]; then

        incorrect=$((incorrect+1))
    else
        correct=$((correct+1))

    fi

done

echo "# of Correct Paths: $correct"
echo "# of Incorrect Paths: $incorrect"
echo "Total # of Files: $N"

If I have a list of 5 files, 4 of which exist, I expect to get the following output (note the echo command wi开发者_Python百科thin the while loop):

1
2
3
4
5
# of Correct Paths: 4
# of Incorrect Paths: 1
Total # of Files: 5

Instead, I get:

1
2
3
4
5
# of Correct Paths: 0
# of Incorrect Paths: 0 
Total # of Files: 0

What happened to the values of these variables? Google had many suggestions of questionable quality and I think I could get it to work with a little more searching, but a brief explanation of what I'm doing wrong would be very helpful.


This is because you are using the useless cat command with a pipe, causing a subshell to be created. Try it without the cat:

while read filename ; do
    N=$((N+1))
    ....
done < file


Alternatively, if you want to keep the cat for some reason, you can fix your script simply by adding this line before the cat instruction:

shopt -s lastpipe 


More generally, sometimes you want to pipe the output of a command. Here's an example that uses process substitution to lint JavaScript files about to be committed by Git and counts the number of files that failed:

# $@ glob
git-staged-files() {
  git diff --cached -C -C -z --name-only --relative --diff-filter=ACMRTUXB "$@"
}

# $@ name
map() { IFS= read -rd $'\0' "$@"; }

declare -i errs=0
while map file; do
  echo "Checking $file..."
  git show ":$file"|
  eslint --stdin --stdin-filename "$file" || ((++errs))
done < <(git-staged-files \*.js)

((errs)) && echo -en "\e[31m$errs files with errors.\e[00m " >&2 || :
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜