[Cialug] Bash looping issue

Daniel A. Ramaley daniel.ramaley at drake.edu
Wed Oct 13 15:16:33 CDT 2010


Wow... people were responding to this? The list seems to have been 
broken for the last few days... i've not been getting any messages and 
thought my post had disappeared into the aether. But just a few minutes 
ago i got 13 messages from CIALUG, and then just now got the one below.

This issue was resolved yesterday by someone on the Tokyo Linux User's 
Group (i cross-posted there since CIALUG seemed to be down):

On 2010-10-12 at 11:37:08, Romeo Theriault wrote:
>Looks like bash is starting the while-read loop in a subshell so
>you're losing your variable assignments when the subshell exits. This
>page talks about a few ways around this:
>
>http://fvue.nl/wiki/Bash:_Piped_%60while-read'_loop_starts_subshell

Thanks for the help though! It is strange that bash sometimes starts a 
subshell.



On 2010-10-13 at 15:12:40, Crouse wrote:
>On Wed, Oct 13, 2010 at 1:14 PM, Crouse <crouse at usalug.net> wrote:
>> ah nm... that went horribly wrong ;)
>> 
>> On Wed, Oct 13, 2010 at 1:12 PM, Crouse <crouse at usalug.net> wrote:
>>> On Wed, Oct 13, 2010 at 11:18 AM, Ken MacLeod <ken at bitsko.slc.ut.us> 
wrote:
>>>> On Tue, Oct 12, 2010 at 10:07 AM, Daniel A. Ramaley
>>>> 
>>>> <daniel.ramaley at drake.edu> wrote:
>>>>> In the example script below, i define an associative array and
>>>>> then make a copy of it using a loop to copy each key/value pair.
>>>>> It seems to work quite nicely... within the loop. Once outside
>>>>> the loop, the copied array loses its data. The bizarre thing is
>>>>> that if i switch the loop construct from a "while" to a "for",
>>>>> it works.
>>>>> 
>>>>> # Comment out the "printf...while" loop and comment in the "for"
>>>>> loop # and it magically starts working. I don't know why.
>>>>> printf "%s\000" "${!ORIG[@]}" | sort -z | while read -d $'\0' key
>>>>> ; do #for key in "${!ORIG[@]}" ; do
>>>> 
>>>> My first thought is that the "while" is running in a pipeline so
>>>> it's running in a subprocess rather than the current process, so
>>>> any variables inside the loop are local to the subprocess.
>>>>  However, I thought I've done that before too and it worked
>>>> right...
>>>> 
>>>> You might try:
>>>> 
>>>>    while read -d $'\0' key <(printf "%s\000" "${!ORIG[@]}" | sort
>>>> -z); do
>>>> 
>>>> so the printf | sort runs in a background process and the while
>>>> stays in the current process.  I've never tried that before but
>>>> it popped up when I went looking for the other kinds of "fancy"
>>>> pipe handling that I know bash has ;-)
>>>> 
>>>>  -- Ken
>>>> _______________________________________________
>>>> Cialug mailing list
>>>> Cialug at cialug.org
>>>> http://cialug.org/mailman/listinfo/cialug
>>> 
>>> If your just copying an array, do you need to use the while loop ?
>>> 
>>> #!/bin/bash
>>> declare -A ORIG
>>> ORIG=(['key 1']='A'
>>>     ['key 2']='B'
>>>     ['key 3']='C')
>>> 
>>> COPY=("${ORIG[@]}")
>>> 
>>> echo -e "\nORIG\n----"
>>> for key in "${!ORIG[@]}" ; do     # Prints the ORIG array.
>>>   echo -e "$key\t${ORIG[$key]}"
>>> done
>>> 
>>> echo -e "\nCOPY\n----"
>>> for key in "${!COPY[@]}" ; do     # Prints COPY only if it was
>>> created echo -e "$key\t${COPY[$key]}" # with "for" loop--prints
>>> nothing if done                              # created with
>>> "while".
>
>Well after some looking, I found this:
>http://mywiki.wooledge.org/BashGuide/Arrays
>"the order of the keys you get back from an associative array using
>the ${!array[@]} syntax is unpredictable; it won't necessarily be the
>order in which you assigned elements, or any kind of sorted order. "
>
>Handy..... not sure this really helps at all, but I did find it
>interesting.
>
>#!/bin/bash
>declare -A ORIG
>ORIG=(['key 1']='A'
>     ['key 2']='B'
>     ['key 3']='C')
>
>declare -A COPY
>
># Create list of keys
>for key in "${!ORIG[@]}" ; do
>echo "$key" >> temp
>done
># Sort list of keys
>cat temp | sort > temp2
>
>while read mykey ; do
>   COPY["${mykey}"]="${ORIG[$mykey]}"
>   #COPY+=(["${key}"]="${ORIG[$key]}") # Alternate form of assignment
>   echo -e "DEBUG:\tProcessing key=\"${mykey}\",
>val=\"${ORIG[$mykey]}\"" # echo -e
>"DEBUG:\t${!COPY[@]}\nDEBUG:\t${COPY[@]}" ; # Shows changes done <
>temp2
>
># remove temp files
>rm temp temp2
>
>#for key in "${!ORIG[@]}" ; do
>#   COPY["${key}"]="${ORIG[$key]}"
>   #COPY+=(["${key}"]="${ORIG[$key]}") # Alternate form of assignment
>#   echo -e "DEBUG:\tProcessing key=\"${key}\", val=\"${ORIG[$key]}\""
>#   echo -e "DEBUG:\t${!COPY[@]}\nDEBUG:\t${COPY[@]}" ; # Shows
>changes #done<( printf "%s\000" "${!ORIG[@]}" | sort -z )
>
>
>echo -e "\nORIG\n----"
>for key in "${!ORIG[@]}" ; do     # Prints the ORIG array.
>   echo -e "$key\t${ORIG[$key]}"
>done
>
>echo -e "\nCOPY\n----"
>for key in "${!COPY[@]}" ; do     # Prints COPY only if it was created
>   echo -e "$key\t${COPY[$key]}" # with "for" loop--prints nothing if
>done                              # created with "while".
>
>~
>~
>~
>~
>~
>~
>~
>~
>~
>~
>~
>~
>~
>[crouse at Archie]  ~
>
>> ./cialug
>
>DEBUG:  Processing key="key 1", val="A"
>DEBUG:  Processing key="key 2", val="B"
>DEBUG:  Processing key="key 3", val="C"
>
>ORIG
>----
>key 1   A
>key 3   C
>key 2   B
>
>COPY
>----
>key 1   A
>key 3   C
>key 2   B
>_______________________________________________
>Cialug mailing list
>Cialug at cialug.org
>http://cialug.org/mailman/listinfo/cialug
__
Daniel A. Ramaley
Network Engineer 2

Dial Center 118, Drake University
2407 Carpenter Ave / Des Moines IA 50311 USA
Tel: +1 515 271-4540
Fax: +1 515 271-1938
E-mail: daniel.ramaley at drake.edu


More information about the Cialug mailing list