sean finney on 16 Sep 2010 12:54:32 -0700


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] Building a command from variables in BASH


ooh, shell programming question!

On Thu, Sep 16, 2010 at 02:40:14PM -0400, Michael Bevilacqua wrote:
> To test, I do:
> 
> echo $VCIDS
> 
> and I get exactly what I want in the string:

is that exactly what you want?  looks like you're missing some quotes.

> | sed -e s/ orarcrc01<->cdp1crc02/ 100000 orarcrc01<->cdp1crc02/g | sed -e
> s/ sdgdcrc01<->cdc1crc02/ 100001 sdgdcrc01<->cdc1crc02/g | sed -e s/
> cindcrc01<->cdc1crc02/ 100002 cindcrc01<->cdc1crc02/g | sed -e s/
> akrdcrc01<->cdp1crc02/ 100003 akrdcrc01<->cdp1crc02/g | sed -e s/
> daldcrc01<->cdp1crc01/ 100004 daldcrc01<->cdp1crc01/g | sed -e s/
> ausrcrc01<->cdc1crc01/ 100005 ausrcrc01<->cdc1crc01/g | sed -e s/
> syrrcrc01<->cdc1crc01/ 100006 syrrcrc01<->cdc1crc01/g | sed -e s/
> manrcrc01<->cdp1crc01/ 100007 manrcrc01<->cdp1crc01/g | sed -e s/
> cdc1crc01<->cdp1crc01/ 100014 cdc1crc01<->cdp1crc01/g | sed -e s/
> cdc1crc02<->cdp1crc02/ 100015 cdc1crc02<->cdp1crc02/g

i.e. sed -e 's/ orarcrc01<->cdp1crc02/ 100000 orarcrc01<->cdp1crc02/g'


> And it fails because $VCIDS is no longer a command, it is now a string, so
> cat wants to read it as so.
> 
> I also tried wrapping it a couple of ways with eval which didn't work
> either.

getting eval right is probably the single trickiest thing in shell
programming i'd say, only surpassed by eval and set together :)

> 
> My question is, how do I rebuild this command and execute it in BASH?
> 

the "easy" suggestion i have is to embed single quotes around everything (if
you are fairly sure that no single quotes will appear in the varibles
themselves, and have complete control over the input).  

so... sed -e '\'s/            `echo $i | cut -d" " -f2`/     `echo $i | cut -d" " -f1` `echo $i | cut -d" " -f2`/g\''

although for stylistic/readability purposes i'd probably do the subshell
commands into local variables.  i.e.:

makeVCID() {
	local f1 f2
	for i in "1000 foo" ....; do
		f1=`echo $i | cut -d" " -f1`
		f2=`echo $i | cut -d" " -f2`
		echo ...
	done
}

and if you're interested in portability (you mentioned that) i suggest
using printf instead of echo, as echo is notoriously unportable.

, anyway, if you keep the pipe in the variable you will need to use
eval, i.e.:

eval cat $FILE1 $VCIDS > $FILE2

though this will fail miserably if FILE1/FILE2/VCIDS contain quotes, shell
metacharacters, word-splitting characters, etc.  so that's a "B-" answer :)

to get the "A+", i would structure the code slightly differently so
that each argument is properly escaped and then passed as positional
parameters via eval+set, and then just call 

	eval set -- "$properly_escaped_and_quoted_arglist"
	cat "$FILE1" | sed "$@".

but this gets into some serious shell voodoo.  if you are curious what
i'm getting at, take a read (or two) through:

	http://www.seanius.net/blog/2009/03/saving-and-restoring-positional-params/

and then

	http://www.seanius.net/blog/2009/03/saving-and-restoring-positional-params-redux/



hth!
	sean

Attachment: signature.asc
Description: Digital signature

___________________________________________________________________________
Philadelphia Linux Users Group         --        http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion  --   http://lists.phillylinux.org/mailman/listinfo/plug