While I was working on toolsapi-shell client, I ran into a quite common bash problem.
#!/bin/bash
POS=0
echo "POS before: $POS"
ls | while read line
do
# do handling for each line (skipped here)
echo "current POS: $POS"
let 'POS += 1'
done
echo "POS after: $POS"
# Result:
# POS before: 0
# current POS: 0
# current POS: 1
# current POS: 2
# POS after: 0
This is not what one or another expects here.
But the reason is simple: since we pipe the output of ls into while, everything between do and done is executed in a subshell. We can check this with the BASH_SUBSHELL variable:
#!/bin/bash
POS=0
echo "POS before: $POS $BASH_SUBSHELL"
ls | while read line
do
# do handling for each line (skipped here)
echo "current POS: $POS $BASH_SUBSHELL"
let 'POS += 1'
done
echo "POS after: $POS $BASH_SUBSHELL"
# Result:
# POS before: 0 0
# current POS: 0 1
# current POS: 1 1
# current POS: 2 1
# POS after: 0 0
The solution:
POS=0
echo "POS before: $POS $BASH_SUBSHELL"
while read line
do
# do handling for each line (skipped here)
echo "current POS: $POS $BASH_SUBSHELL"
let "POS += 1"
done<<EOF
`ls`
EOF
echo "POS after: $POS $BASH_SUBSHELL"
# Result:
# POS before: 0 0
# current POS: 0 0
# current POS: 1 0
# current POS: 2 0
# POS after: 2 0
Because we don't use | here to feed the while loop, there is no extra subshell while running the loop. The important part is:
ls | while read line
do
# your logic
done
becomes (mind the backticks around ls!)
while read line
do
# your logic
done<<EOF
`ls`
EOF