This is probably going to be very simple but i came across something i can't quite explain. Here is the situation: i have a list of files, which i'd like to process one by one (get the size, make some tests, whatever) and generate some statistics using different variables.
Something similar to this:
u=0
ls|while read f; do
#until [ $u -gt 5 ]; do
#for f in `ls `; do
echo inside u=$u
let "u+=1"
done
echo outside u=$u
And here are the results (there are 3 files in the current directory):
So basically the variable u appears to get re-initialised somehow.
Using until or a classic for loop u keeps its value after the loop is executed, like this:
So what's the deal ? That's under bash. Ksh gives similar results to the other loops.
It's not the different kinds of loops that are doing it -- it's the pipe that does it. By putting your while loop behind a pipe, you are executing it inside a subshell. Values get changed in the subshell, not the main one, and don't get copied back.
ksh organizes pipes in a different order than other Bourne shells. The innermost loop runs in the current shell while the outermost loop runs in the subshell. This is a KSH-only feature.
Depending on your goal, there are various ways to circumvent or just plain avoid this. This is a useless use of ls * for instance -- a situation where you might as well be using the * operator instead of the external ls utility.
for X in *
do
let "u+=1"
done
The 'for' loop overcomes this by putting ls in backticks, which runs it first, and sets the value in a variable. But this is not recommended as it will be confused by filenames with spaces in them.
@Corona688: I too thought the same, and tried to check this by printing the pid of shell before entering while loop and inside while loop. Pid's are same. If its invoking a sub-shell it should print the pid of the sub-shell inside while loop, right?
#! /bin/bash
u=0
echo "before while, pid = $$"
ls | while read x
do
echo "inside while, pid = $$"
((u++))
done
# bash --version
GNU bash, version 3.1.17(1)-release (i686-redhat-linux-gnu)
# ./test.sh
before while, pid = 6435
inside while, pid = 6435
inside while, pid = 6435
inside while, pid = 6435