[Discuss] Bourne Shell variable assignment question

31 views
Skip to first unread message

Jerry Feldman

unread,
Dec 15, 2011, 3:57:04 PM12/15/11
to Boston Linux and Unix
I have not done my homework on this as much as I should.
A coworker needs to set variable names and values input from another
file. Normally, I would source that file, but he specifically wants to
parse the file.
So, in simple terms, he has a file that has something like:
var1=foo

Instead of sourcing he wants to parse the file using readline so he
reads the variable name, then he wants to assign a variable of the same
name.
So, in his code he has something like
readline
... - code to parse the line
Where varname contains the variable name(eg var1), and value contains
the value(eg foo)

--
Jerry Feldman <g...@blu.org>
Boston Linux and Unix
PGP key id:3BC1EB90
PGP Key fingerprint: 49E2 C52A FC5A A31F 8D66 C0AF 7CEA 30FC 3BC1 EB90


Matt Shields

unread,
Dec 15, 2011, 4:12:00 PM12/15/11
to Jerry Feldman, Boston Linux and Unix

> _______________________________________________
> Discuss mailing list
> Dis...@blu.org
> http://lists.blu.org/mailman/listinfo/discuss
>
>
Maybe not the most elegant way, but it works. See below

Matts-MacBook-Pro:temp matt$ cat test1.sh
#!/bin/bash
var1=dog
var2=cat
var3=cow

Matts-MacBook-Pro:temp matt$ cat test2.sh
#!/bin/bash
myvar=`cat test1.sh | grep var2 | cut -d"=" -f2`
echo $myvar

Matts-MacBook-Pro:temp matt$ bash test2.sh
cow

Matthew Shields
Owner
BeanTown Host - Web Hosting, Domain Names, Dedicated Servers, Colocation,
Managed Services
www.beantownhost.com
www.sysadminvalley.com
www.jeeprally.com
Like us on Facebook <http://www.facebook.com/beantownhost>
Follow us on Twitter <https://twitter.com/#!/beantownhost>
_______________________________________________
Discuss mailing list
Dis...@blu.org
http://lists.blu.org/mailman/listinfo/discuss

Matt Shields

unread,
Dec 15, 2011, 4:13:29 PM12/15/11
to Jerry Feldman, Boston Linux and Unix

Sorry, first file should be the follow. That's why the output was wrong.

Matts-MacBook-Pro:temp matt$ cat test1.sh
#!/bin/bash
var1=dog

var2=cow
var3=cat

Ben Eisenbraun

unread,
Dec 15, 2011, 4:22:15 PM12/15/11
to Jerry Feldman, Boston Linux and Unix
On Thu, Dec 15, 2011 at 03:57:04PM -0500, Jerry Feldman wrote:
> I have not done my homework on this as much as I should.
> A coworker needs to set variable names and values input from another
> file. Normally, I would source that file, but he specifically wants to
> parse the file.
> So, in simple terms, he has a file that has something like:
> var1=foo
>
> Instead of sourcing he wants to parse the file using readline so he

Readline is a library for that command line apps can use for command
editing and history. It's not part of the shell, and I don't think it can
be used the way you're suggesting.

-b

--
the wages of gin is breath. <anonymous>

Peter Doherty

unread,
Dec 15, 2011, 4:25:38 PM12/15/11
to Boston Linux and Unix

On Dec 15, 2011, at 15:57 , Jerry Feldman wrote:

> I have not done my homework on this as much as I should.
> A coworker needs to set variable names and values input from another
> file. Normally, I would source that file, but he specifically wants to
> parse the file.
> So, in simple terms, he has a file that has something like:
> var1=foo
>
> Instead of sourcing he wants to parse the file using readline so he
> reads the variable name, then he wants to assign a variable of the same
> name.
> So, in his code he has something like
> readline
> ... - code to parse the line
> Where varname contains the variable name(eg var1), and value contains
> the value(eg foo)


Matt's suggestion calls grep and cut for each variable. This creates a lot of process churn, and will become a slowdown if you have a huge number of variables. But you probably don't.

Are you restricted to Bourne, or can you use BASH?

I know BASH can do fancy string manipulation, but I don't think it's doable in Bourne.
In BASH, i'd do something like this: (assuming I understood your question correctly)

(my input file)
$> cat file
var1=foo
var2=bar
var3=badidea

(my one liner)
$> while read line ; do export ${line%%=*}=${line#*=} ; done < file


refs:
http://linuxgazette.net/18/bash.html

Of course, one has to ask why your co-worker is doing this, and not just sourcing the file.
Also, my example will break if you have an equal sign in your variable name or value name.


-peter

Richard Pieri

unread,
Dec 15, 2011, 4:27:34 PM12/15/11
to blu and Unix
On 12/15/2011 4:25 PM, Peter Doherty wrote:
> Of course, one has to ask why your co-worker is doing this, and not just sourcing the file.
> Also, my example will break if you have an equal sign in your variable name or value name.

This. Sourcing the file is going to be the fastest and most reliable
way to do it.

--
--Rich P.

Jerry Feldman

unread,
Dec 15, 2011, 4:31:03 PM12/15/11
to Boston Linux and Unix
On 12/15/2011 04:22 PM, Ben Eisenbraun wrote:
> On Thu, Dec 15, 2011 at 03:57:04PM -0500, Jerry Feldman wrote:
>> I have not done my homework on this as much as I should.
>> A coworker needs to set variable names and values input from another
>> file. Normally, I would source that file, but he specifically wants to
>> parse the file.
>> So, in simple terms, he has a file that has something like:
>> var1=foo
>>
>> Instead of sourcing he wants to parse the file using readline so he
> Readline is a library for that command line apps can use for command
> editing and history. It's not part of the shell, and I don't think it can
> be used the way you're suggesting.
>
> -b
>
> --
> the wages of gin is breath. <anonymous>
>
I meant read and not readline.
The real issue is:
I have a variable called varname that contains "myvar"
I want to be able to use the content of varname to name a variable so
that myvar becomes a variable.
In the specific case, my coworker is reading something like"
myvar=foo

What he wants to do is the equivalent of sourcing this code, but he
wants to read it from a file.
#/bin/sh
...
IFS="=" # This is not the correct way, but I'm just using it as an example
read varname varvalue
### In this case varname contains "myvar", and vavalue contains "foo"
But, what he wants to end up with is a variable called "myvar"
containing "foo".

### What he wants to do does not make sense to me when sourcing the file
will work just fine.

Ben Eisenbraun

unread,
Dec 15, 2011, 4:34:35 PM12/15/11
to dis...@blu.org
On Thu, Dec 15, 2011 at 04:27:34PM -0500, Richard Pieri wrote:
> On 12/15/2011 4:25 PM, Peter Doherty wrote:
> > Of course, one has to ask why your co-worker is doing this, and not just sourcing the file.
> > Also, my example will break if you have an equal sign in your variable name or value name.
>
> This. Sourcing the file is going to be the fastest and most reliable
> way to do it.

And if you're really restricted to Bourne and not Bash, then you have to
use '.', not 'source'.

You can play tricks with 'eval' too if you'd like.

-b

--
character is fate. <heraclitus>

Jerry Feldman

unread,
Dec 15, 2011, 4:35:09 PM12/15/11
to dis...@blu.org
On 12/15/2011 04:27 PM, Richard Pieri wrote:
> On 12/15/2011 4:25 PM, Peter Doherty wrote:
>> Of course, one has to ask why your co-worker is doing this, and not
>> just sourcing the file.
>> Also, my example will break if you have an equal sign in your
>> variable name or value name.
>
> This. Sourcing the file is going to be the fastest and most reliable
> way to do it.
>
This is 100% agreed. The issue is that he does not want to source the
file and I have not been able to talk him out of it. In the past I have
written scripts where you could read the name of a variable, and then
convert it to a variable name, but I don't think I've done it in Bourne
of BASH.

Chris Tyler

unread,
Dec 15, 2011, 4:51:36 PM12/15/11
to Boston Linux and Unix
On Thu, 2011-12-15 at 16:35 -0500, Jerry Feldman wrote:
> On 12/15/2011 04:27 PM, Richard Pieri wrote:
> > On 12/15/2011 4:25 PM, Peter Doherty wrote:
> >> Of course, one has to ask why your co-worker is doing this, and not
> >> just sourcing the file.
> >> Also, my example will break if you have an equal sign in your
> >> variable name or value name.
> >
> > This. Sourcing the file is going to be the fastest and most reliable
> > way to do it.
> >
> This is 100% agreed. The issue is that he does not want to source the
> file and I have not been able to talk him out of it. In the past I have
> written scripts where you could read the name of a variable, and then
> convert it to a variable name, but I don't think I've done it in Bourne
> of BASH.


There are lots of options:

#!/bin/sh
# equivalent to sourcing the file
while read LINE
do
eval "$LINE"
done <datafile


#!/bin/bash
# same as above, bash/ksh only
for LINE in $(<datafile)
do
eval "$LINE"
done

#!/bin/sh
# similar, but rejects lines that are not NAME=VALUE or have spaces
# also exports all variables processed
egrep "^[^= ]+=[^= ]+$" datafile|while read LINE
do
eval "export $LINE"
done


You could easily parse out the name and value separately, but there's no
reason to, because you're going to end up putting them on either side of
an equal sign in an eval anyways.

-Chris

Jerry Feldman

unread,
Dec 15, 2011, 4:56:58 PM12/15/11
to dis...@blu.org
Just want to simplify.
#!/bin/bash
varname=myvar
varvalue=foo
--- do something to create myvar.
myvar=$varvalue
echo $myvar

Jerry Feldman

unread,
Dec 15, 2011, 5:16:32 PM12/15/11
to dis...@blu.org
Thanks guys.
I have several workable solutions for him. The underlying issue is that
he wants to prevent malicious code. In the context he is working on, I
don't think that is a risk, but using egrep to reject any lines that are
not in the form 'var=value'. I also think that his script must be
Bourne, not BASH.

Chuck Anderson

unread,
Dec 15, 2011, 5:31:37 PM12/15/11
to dis...@blu.org
On Thu, Dec 15, 2011 at 05:16:32PM -0500, Jerry Feldman wrote:
> Thanks guys.
> I have several workable solutions for him. The underlying issue is that
> he wants to prevent malicious code. In the context he is working on, I
> don't think that is a risk, but using egrep to reject any lines that are
> not in the form 'var=value'. I also think that his script must be
> Bourne, not BASH.

I believe eval is susceptible to the same risks as source.

Dan Kressin

unread,
Dec 15, 2011, 5:45:10 PM12/15/11
to Jerry Feldman, dis...@blu.org


I think 'declare' might be what you were looking for, although AFIACT it's not part of Bourne.  But this works with BASH when invoked as 'sh'.  (Note needing to reset IFS midstream so that declare doesn't throw away the = it needs..)


[root@kressin01v ~]# cat myvars
var1=foo
var2=bar
var3=baz
[root@kressin01v ~]# cat readvar.sh
#!/bin/sh
#
OLDIFS="$IFS"
IFS="="
echo "BEFORE"
echo "====="
set | grep "^var"
echo "====="
while read myvar myvalue
do
        echo "$myvar: $myvalue"
        IFS="$OLDIFS"
        declare $myvar="$myvalue"
        IFS="="
done

echo "AFTER"
echo "====="
set | grep "^var"
echo "====="

echo "var1: $var1"
echo "var2: $var2"
echo "var3: $var3"
[root@kressin01v ~]# cat myvars | ./readvar.sh
BEFORE
=====
=====
var1: foo
var2: bar
var3: baz
AFTER
=====
var1=foo
var2=bar
var3=baz
=====
var1: foo
var2: bar
var3: baz
[root@kressin01v ~]#

I could see this (rather than sourcing directly) being potentially useful if you didn't know what variables would be in the file and wanted to keep a list or something without rereading the file.  Though there are surely better / less kludgy ways of accomplishing that particular goal as well.

-Dan

Richard Pieri

unread,
Dec 15, 2011, 7:14:03 PM12/15/11
to blu and Unix
On Dec 15, 2011, at 4:35 PM, Jerry Feldman wrote:
>
> This is 100% agreed. The issue is that he does not want to source the
> file and I have not been able to talk him out of it. In the past I have
> written scripts where you could read the name of a variable, and then
> convert it to a variable name, but I don't think I've done it in Bourne
> of BASH.

You pretty well have to politely inform this person that he's an idiot. You could do something like this:

for line in `cat file.txt`; do
eval ${line}
done

Which has the "benefit" of roughly duplicating source in slow motion. You can't do it with readline because the assignment fails. bash won't use an environment variable as a variable name, at least not directly:

$ foo=bar
$ ${foo}=baz
bash: bar=baz: command not found

"Prevent malicious code"? It's a shell script. Use the Mk.I Eyeball. Because I can stuff malicious code into an "x=y" statement that matches his egrep without any difficulty at all:

foo="`rm -rf *`"

Gordon Ross

unread,
Dec 15, 2011, 11:09:07 PM12/15/11
to Jerry Feldman, dis...@blu.org
On Thu, Dec 15, 2011 at 3:57 PM, Jerry Feldman <g...@blu.org> wrote:

Here's a reasonable method, snipped from some
scripts I wrote a while back. Hope it helps...


USAGE="FIX ME"

parse_config()
{
case "$1" in
ip_addr=*) ip_addr="${1#*=}";;
netmask=*) netmask="${1#*=}";;
dns_srv1=*) dns_srv1="${1#*=}";;
dns_srv2=*) dns_srv2="${1#*=}";;
dns_dom=*) dns_dom="${1#*=}";;
*) echo $USAGE >&2; exit 1;;
esac
}

print_config()
{
echo "ip_addr=$ip_addr"
echo "netmask=$netmask"
echo "dns_srv1=$dns_srv1"
echo "dns_srv2=$dns_srv2"
echo "dns_dom=$dns_dom"
}

while read line
do
parse_config "$line"
done < "$config_file"


# Here is some test output, given the input:
ip_addr=1.2.3.4
dns_srv1=1.2.3.1
$ config_file=/tmp/fubar bash /tmp/parse.ksh
ip_addr=1.2.3.4
netmask=
dns_srv1=1.2.3.1
dns_srv2=
dns_dom=

Jerry Feldman

unread,
Dec 16, 2011, 7:28:31 AM12/16/11
to dis...@blu.org
On 12/15/2011 07:14 PM, Richard Pieri wrote:
> On Dec 15, 2011, at 4:35 PM, Jerry Feldman wrote:
>> This is 100% agreed. The issue is that he does not want to source the
>> file and I have not been able to talk him out of it. In the past I have
>> written scripts where you could read the name of a variable, and then
>> convert it to a variable name, but I don't think I've done it in Bourne
>> of BASH.
> You pretty well have to politely inform this person that he's an idiot. You could do something like this:
He is not a trained programmer. I have not seen some of the other
programs he has written. I'm usually pretty critical of inefficient
code. One thing I do in nearly all of my scripts is to set up variables
for commants, such as:
RM=/bin/rm
I also set up a prefix, or path to where my script is run from. So,
let's say my code is in /foo/bin, but there is a symlink in
/usr/local/bin. I set up the prefix so that it resolves the symlink so
when I source other files, I get them from the exact same place. This is
simple in BASH, but a bit tricky in tcl.
Reply all
Reply to author
Forward
0 new messages