Issue
I have the following problem. Let´s assume that $@
contains only valid files. Variable file
contains the name of the current file (the file I'm currently "on"). Then variable element
contains data in the format file:function
.
Now, when variable element is not empty, it should be put into the array. And that's the problem. If I echo element
, it contains exactly what I want, although it is not stored in array, so for cycle doesn't print out anything.
I have written two ways I try to insert element into array, but neither works. Can you tell me, What am I doing wrong, please?
I'm using Linux Mint 16.
#!/bin/bash
nm $@ | while read line
do
pattern="`echo \"$line\" | sed -n \"s/^\(.*\):$/\1/p\"`"
if [ -n "$pattern" ]; then
file="$pattern"
fi
element="`echo \"$line\" | sed -n \"s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p\"`"
if [ -n "$element" ]; then
array+=("$element")
#array[$[${#array[@]}+1]]="$element"
echo element - "$element"
fi
done
for j in "${array[@]}"
do
echo "$j"
done
Solution
Your problem is that the while
loop runs in a subshell because it is the second command in a pipeline, so any changes made in that loop are not available after the loop exits.
You have a few options. I often use {
and }
for command grouping:
nm "$@" |
{
while read line
do
…
done
for j in "${array[@]}"
do
echo "$j"
done
}
In bash
, you can also use process substitution:
while read line
do
…
done < <(nm "$@")
Bash also supports an option shopt -s lastpipe
which runs the last process in a pipeline in the current shell environment so that changes made by the last part of the pipeline are available to the rest of the script. Then you do not need the command grouping notation or process substitution.
Also, it is better to use $(…)
in place of back-quotes `…`
(and not just because it is hard work getting back quotes into markdown text!).
Your line:
element="`echo \"$line\" | sed -n \"s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p\"`"
could be written:
element="$(echo "$line" | sed -n "s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p")"
or even:
element=$(echo "$line" | sed -n "s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p")
It really helps when you need to nest command substitution operations. For example, to list the lib
directory adjacent to where gcc
is found:
ls -l $(dirname $(dirname $(which gcc)))/lib
vs
ls -l `dirname \`dirname \\\`which gcc\\\`\``/lib
I know which I find easier!
Answered By - Jonathan Leffler Answer Checked By - Cary Denson (WPSolving Admin)