Retaining value outside loop


Login or Register to Reply

 
Thread Tools Search this Thread
# 1  
Old 3 Weeks Ago
Retaining value outside loop

Hi,

I m new to shell scripting. I did some research and understand that unix treats while and other loops as new shell and hence the variable loose its value outside of the loop.

I found solution for integer variable but in mycase this is a string variable.

here variable loc is a multiline string.

Code:
totalstr=""
echo "$loc" | while IFS= read -r line ; do
totalstr=$totalstr,$line;
done
echo "Final Output:$totalstr"

I wish the get the multiline string in variable totalstr this format: string1,string2,string3,string4

But currently it is blank as it looses scope. Can you let me know what should be done ?
# 2  
Old 3 Weeks Ago
Hi,
maybe so
Code:
totalstr=$(grep -o "\S\+" <<<"$loc" | paste -sd,)
echo "Final Output:$totalstr"

# 3  
Old 3 Weeks Ago
Quote:
Originally Posted by nezabudka
Hi,
maybe so
Code:
totalstr=$(grep -o "\S\+" <<<"$loc" | paste -sd,)
echo "Final Output:$totalstr"

Tried this suggestion but i see nothing empty output:

Code:
more list.sh
#!/bin/bash

loc=$1

totalstr=""

totalstr=$(grep -o "\S\+" <<<"$loc" | paste -sd,)

echo "FINAL:$totalstr"

Quote:
OUTPUT:
/opt/myscripts/list.sh 'string1
string2
string3
'
FINAL:
My system is Linux.

Please suggest.
# 4  
Old 3 Weeks Ago
Try double quoting $1 when assigning it to the loc variable, so <NL> won't be lost.


If your target is to replace <NL> chars in a variable by commas, try

Code:
totalstr=${loc//$'\n'/,}

or even
Code:
totalstr=${1//$'\n'/,}

This User Gave Thanks to RudiC For This Post:
nezabudka (3 Weeks Ago)
# 5  
Old 3 Weeks Ago
Quote:
Originally Posted by knowyrtech
I m new to shell scripting. I did some research and understand that unix treats while and other loops as new shell and hence the variable loose its value outside of the loop.
This is not completely wrong but also not completely right:

"UNIX" is completely indifferent about this topic. This is a property of the shell and hence the behavior you see depends on which shell you use (and how you configure it).

Most of todays shells have a common ancestor, the "Bourne Shell", which indeed shows the behavior you noticed. In the following sample:

Code:
process | while read line ; do
     var=<something>
done

the while-do..done-loop is the second part of a pipeline and therefore executed in a subshell. Therefore, whatever value you assign to "var", it will be lost outside the loop because after the loop the subshell is simply closed. Notice that defining it up front like this:

Code:
var=<value>
process | while read line ; do
     var=<something>
done

will not help: the variable "var" in the subshell may have the same name as the variable "var" in the script shell but they are not the same at all. The only way you can overcome this is by replacing the pipeline with a redirection:

Code:
while read line ; do
     var=<something>
done < $(process)

Today, the real Bourne Shell is rarely used at all (IIRC it is from the beginning of the eighties) but mostly one of its two main successors: Korn Shell (ksh) and the Bourne Again Shell (bash). Both are (almost) completely backwards compatible with the Bourne Shell which means every shell script written for Bourne Shell should run on Korn shell as well as bash.

In ksh this (rather unintuitive, IMHO) behavior of the Bourne Shell was abandoned and therefore the two examples above work absolutely identical.

Code:
i=1
while [ i -le 100 ] ; do
     (( i += 1 ))
done
print $i

This will produce "100" as output in ksh and not "1", like in the Bourne Shell.

In bash, however, the original behavior of the Bourne Shell was retained and hence would produce "1" too. But because that was unintuitive even for the bash programmers in bash 4 (? i am not sure about the exact version) the shell-option "lastpipe" was introduced. If you set that with

Code:
shopt -s lastpipe

bash will work exactly like ksh (in this regard). Notice, though, that you might still come across bash versions which will not understand this configuration. You will have to do it either this way (redirection):

Code:
totalstr=""
while IFS= read -r line ; do
     totalstr=$totalstr,$line;
done < $(echo "$loc")
echo "Final Output:$totalstr"

or you can do it this way (a so-called "here-document"):

Code:
totalstr=""
while IFS= read -r line ; do
     totalstr=$totalstr,$line;
done <<- EOF
     echo "$loc"
EOF
echo "Final Output:$totalstr"

I hope this helps.

bakunin
This User Gave Thanks to bakunin For This Post:
rbatte1 (2 Weeks Ago)
# 6  
Old 3 Weeks Ago
Why use read for a variable? This is exactly what a for loop is for:

Code:
OLDIFS="$IFS"
IFS="
"
for line in $loc
do
        totalstr=$totalstr,$line;
done
IFS="$OLDIFS"

If your multiline variable is simple enough, i.e. no embedded whitespace besides newline, leading, and trailing -- you can omit the IFS stuff for the same result.
This User Gave Thanks to Corona688 For This Post:
nezabudka (3 Weeks Ago)
# 7  
Old 3 Weeks Ago
A correction:
Code:
i=1
while [ i -le 100 ] ; do
  (( i += 1 ))
done
print $i

produces 101 in ksh and errors in Bourne shell.
While the following
Code:
i=1
while [ $i -le 100 ] ; do
  i=`expr $i + 1`
done
echo $i

runs on both,
but might produce 1 in an old Bourne shell because it always runs the while loop in a sub shell.
A later Bourne shell has got a fix, but seeing a redirection it still runs the sub shell.
Code:
i=1
while [ $i -le 100 ] ; do
  i=`expr $i + 1`
done </dev/null
echo $i

That means all Bourne shells do not work with the previously suggested <<EOF redirection.
The Posix shell has got it all fixed. And all Posix-compatible shells.
But a pipe really forces a sub shell. Because it is the last part of the pipe. Compare with a simple command
Code:
echo "a:b:c:" | IFS=":" read a b c

Only the ksh has got the (incompatible) modification to run the last part of the pipe in the current shell.

Back to the initial post - that works only in ksh.
The following is portable to all Posix-compatible shells:
Code:
totalstr=$(
# sub shell starts
  sep=""
  echo "$loc" |
  while IFS= read -r line ; do
    # the pipe might force a sub sub shell
    printf "%s" "$sep$line"
    sep=","
  done
# sub shell ends
)
echo "Final Output:$totalstr "

As you can see, a sub shell inherits everything from the current shell, but not vice versa.
Login or Register to Reply

|
Thread Tools Search this Thread
Search this Thread:
Advanced Search

More UNIX and Linux Forum Topics You Might Find Helpful
Retaining latest file anil029 Shell Programming and Scripting 7 05-16-2014 05:44 AM
Retaining whitespaces... kumarjt Shell Programming and Scripting 1 06-13-2013 09:30 AM
Perl: Problem in retaining values after each loop anurupa777 Shell Programming and Scripting 1 09-27-2012 02:49 PM
Help with retaining variable scope justchill Shell Programming and Scripting 6 09-16-2011 06:58 AM
Retaining Pipeline values sachinnayyar Shell Programming and Scripting 4 08-16-2011 08:03 AM
help in retaining leading zero udelalv Shell Programming and Scripting 2 08-16-2011 05:56 AM
Variable value not retaining outside function ajincoep Shell Programming and Scripting 7 09-02-2010 08:04 AM
Retaining default OFS amicon007 Shell Programming and Scripting 3 01-15-2009 10:39 AM
Retaining spaces between words RcR Shell Programming and Scripting 7 07-30-2008 02:29 AM
retaining file path c00kie88 Shell Programming and Scripting 2 05-22-2008 12:18 AM
Retaining Spaces within a word RcR UNIX for Dummies Questions & Answers 0 09-09-2007 11:19 PM
retaining the evironment varaibles... priya444 Linux 5 03-23-2007 05:50 AM
Retaining tar.gz after gunzip devs Shell Programming and Scripting 4 02-26-2007 10:41 PM
variable not retaining value gillbates Shell Programming and Scripting 5 11-16-2005 05:16 PM
Retaining value in var for flag. videsh77 Shell Programming and Scripting 4 05-31-2005 10:44 PM