Why is the array empty after the while loop?

I try to initialize an array in bash-4.2 next way:

ring=()
ls -las | tail -n +4 | while read line
> do
> ring+=("$line")
> echo ${ring[-1]}
> done
3924 -rw-r--r-- 1 username group 4015716 Mar 23 15:14 script.jar
4 -rw-r--r-- 1 username group 9 Feb 29 12:40 rec.lst
5541 -rw-r--r-- 1 username group 5674226917 Mar 28 15:25 debug.out
8 -rw-r--r-- 1 username group 6135 Mar 25 12:16 script.class
8 -rw-r--r-- 1 username group 6377 Mar 25 11:57 script.java
8 -rwxr-xr-x 1 username group 4930 Mar 8 15:21 script-0.0.0.sh
8 -rwxr-xr-x 1 username group 6361 Mar 28 15:27 script-0.0.1.sh
echo ${ring[0]}

echo "${ring[0]}"

echo "${ring[@]}"

What is wrong, why i get empty array after the finish of the loop?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Your problem is that in a pipeline ( command1 | command2 | command3 ... ) the commands are ran in subshells. Variables are not shared between subshells or between subshells and the main shell. The ring in the while loop is different than the ring in the main shell.

One way to overcome this is to use process substitution:

while read line;  do  ring+=("$line");  echo ${ring[-1]};  done < <(ls -las|tail -n +4)

The <(command) syntax is called process substitution and will redirect the output of the command to a named pipe. Which is then redirected with the familiar < as if it was a file. When you use <, there is no subshell, so the ring variable will be set.

Note that there is a shell builtin command to fill an array from the lines of a file:

mapfile -t ring < <(ls -las | tail -n +4)

Method 2

This should work fine:

ring=()
while read line
do
ring+=("$line")
echo ${ring[-1]}
done < <(ls -las | tail -n +4)

Source: http://wiki.bash-hackers.org/syntax/arrays

Method 3

The reason is while loop is executed in a subshell due to the fact it is piped. Subshell uses a copy of the parent shell environment and does not pass it back when the subshell quits.

for bash you can use command grouping workaround, note curly brackets added

ls -las | tail -n +4 | { while read line;  do  ring+=("$line");  echo ${ring[-1]};  done;  echo ${ring[0]}; }


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x