Variables set in a bash 'while read' loop are unset after it
The problem is that you add the elements in a subshell. To elaborate:
command1 | command2
causes command2
to be executed in a subshell, which is a separate execution environment. This implies that the variables set in command2
are not available to the current shell, whose execution environment is not affected. You could instead use process substitution to achieve the same:
while read line; do
...
done < <(ls -l)
Please note that parsing ls
is not recommended; try using find
instead.
A variable modified inside a while loop is not remembered
echo -e $lines | while read line
...
done
The while
loop is executed in a subshell. So any changes you do to the variable will not be available once the subshell exits.
Instead you can use a here string to re-write the while loop to be in the main shell process; only echo -e $lines
will run in a subshell:
while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done <<< "$(echo -e "$lines")"
You can get rid of the rather ugly echo
in the here-string above by expanding the backslash sequences immediately when assigning lines
. The $'...'
form of quoting can be used there:
lines=$'first line\nsecond line\nthird line'
while read line; do
...
done <<< "$lines"
Variables getting reset after the while read loop that reads from a pipeline
I ran into this problem yesterday.
The trouble is that you're doing find $loc -name "*.bsp" | while read
. Because this involves a pipe, the while read
loop can't actually be running in the same bash process as the rest of your script; bash has to spawn off a subprocess so that it can connect the the stdout of find
to the stdin of the while
loop.
This is all very clever, but it means that any variables set in the loop can't be seen after the loop, which totally defeated the whole purpose of the while
loop I was writing.
You can either try to feed input to the loop without using a pipe, or get output from the loop without using variables. I ended up with a horrifying abomination involving both writing to a temporary file AND wrapping the whole loop in $(...)
, like so:
var="$(producer | while read line; do
...
echo "${something}"
done)"
Which got me var set to all the things that had been echoed from the loop. I probably messed up the syntax of that example; I don't have the code I wrote handy at the moment.
Variable value reset after loop
Do it this way:
#!bin/bash
#
ls *.csv > /tmp/CSVfiles
ADDITIONALTABLES="FXRATES ANVIL"
while read staticFile
do
staticTable=`basename $staticFile`
echo $staticTable
ADDITIONALTABLES="$ADDITIONALTABLES ${staticTable%.csv}"
echo "in $ADDITIONALTABLES"
done < /tmp/CSVfiles
echo "out $ADDITIONALTABLES"
Like others pointed out in the comments, the pipe runs in a subshell. But if you use redirection like above it works.
Variable incremented in bash while loop resets to 0 when loop finishes
A pipe spawns a subshell, use a process substitutions instead:
while read -r f
do
count=$(($count+1))
echo "Count is at ${count}"
done < <(ls)
Also note that you shouldn't parse the output of ls.
And your example seems to count numbers of files and directories in current directory, which can be done with find and wc:
find -maxdepth 1 -mindepth 1 -printf "\n" | wc -l
or you can avoid ls
with a for loop and globbing:
for f in * .*; do
[ -e "$f" ] || continue
count=$((count + 1))
echo "Count is at ${count}"
done
Shell variables set inside while loop not visible outside of it
When you pipe into a while
loop in Bash, it creates a subshell. When the subshell exits, all variables return to their previous values (which may be null or unset). This can be prevented by using process substitution.
LONGEST_CNT=0
while read -r line
do
line_length=${#line}
if (( line_length > LONGEST_CNT ))
then
LONGEST_CNT=$line_length
LONGEST_STR=$line
fi
done < <(find samples/ ) # process substitution
echo $LONGEST_CNT : $LONGEST_STR
Bash: Retain variable's value after while loop
When you use a pipe you are automatically creating subshells so that the input and output can be hooked up by the shell. That means that you cannot modify the parent environment, because you're now in a child process.
As anubhava said though, you can reformulate the loop to avoid the pipe by using process substitution like so:
while read commit; do
TEMP_FLAG=true
done < <( git log --pretty="%H|%s" --skip=1 )
printf "%s\n" "$TEMP_FLAG"
bash while read loop arguments from variable issue
operators_list=$'andrii,bogdan,eios,fre,kuz,pvm,sebastian,tester,tester2,vincent,ykosogon'
So you have strings separated by ,
. You can do that multiple ways:
- using bash arrays:
IFS=, read -a operators <<<$operators_list
for op in "${operators[@]}"; do
echo "$op"
done
- Using a while loop, like you wanted:
while IFS= read -d, -r op; do
echo "$op"
done <<<$operators_list
- Using xargs, because why not:
<<<$operators_list xargs -d, -n1 echo
The thing with IFS and read delimeter is: read
reads until delimeter specified with -d
. Then after read
has read a full string (usually whole line, as default delimeter is newline), then the string is splitted into parts using IFS
as delimeter. So you can:
while IFS=: read -d, -r op1 op2; do
echo "$op1" "$op2"
done <<<"op11:op12,op12:op22"
Related Topics
Specifying Non-Standard Baud Rate for Ftdi Virtual Serial Port Under Linux
Why Characters Received in Serial Connection Only After Pressing Enter
Iterating Over Each Line of Ls -L Output
Remote Linux Server to Remote Linux Server Dir Copy. How
Http Debugging Proxy for Linux and MAC
How to Find Files That Only Have Certain Permission for Owner
Is There an Acceptable Linux Targeted Gui Client for Git-Svn
X Keypress/Release Events Capturing Irrespective of Window in Focus
What Is The Point of "Grep -Q"
Does The Linux Scheduler Needs to Be Context Switched
What's the Difference Between ./Script.Sh and Bash Script.Sh
Variables Set in a Bash 'While Read' Loop Are Unset After It
Counting Number of Directories in a Specific Directory
Linux Command Line Howto Accept Pairing for Bluetooth Device Without Pin
Unix: Differencebetween Source and Export
Command Line Arduino Compiling and Uploading