The following line creates file_c-6.txt
but outputs 5
:
$ i=5; ls file_a-${i}.txt file_b-${i}.txt > file_c-$(( ++i )).txt; echo $i
5
$ cat file_c-6.txt
file_a-5.txt
file_b-5.txt
If one removes >
it would list file_c-6.txt
and output 5
:
I can't understand why it doesn't keep the value of i
in the first example.
$ i=5; ls file_a-${i}.txt file_b-${i}.txt file_c-$(( ++i )).txt; echo $i
file_a-5.txt file_b-5.txt file_c-6.txt
6
Best Answer
If you run this under strace, you can see that the version that uses
ls
starts up the command in a subshell, where the version which uses echo executes it all in the existing shell.Compare the output of
against
You'll see in the first:
And in the second:
In this last example, you see the
clone
into a new process (from 1258 -> 1259), so now we're in a subprocess. The opening of file_c-6.txt which means that we've evaluated$((++i))
in the subshell, and the execution ofls
with its stdout set to that file.Finally, we see that the subprocess exits, we reap the child, then we continue with where we left off... with
$i
set to 5, and that's what we echo out again.(Remember variable changes in a subprocess do not percolate up to the parent process, unless you do something explicitly in the parent to grab the child's changes)