Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

eval a command

2 views
Skip to first unread message

SiKing

unread,
Sep 18, 2006, 11:37:06 AM9/18/06
to
Hi all,

I was wondering if someone could lend me an explanation. :)

I am working in gnu-bash, version 3.
I have a list of commands (scripts, written in various scripting languages) in a
text file, that my script reads in one at a time, and then I try to execute.
What is the difference between the following ways of executing these:
$executable
`$executable`
eval $executable

The first and the third do what I want, but I am not sure why. The second (my
first attempt) did not work correctly.
Any insight is appreciated.

TIA, SK.


--
"One of these days, milkshake, BOOM!"
-- Evil Midnight Bomber What Bombs at Midnight
-----
Candy for spammers:
http://members.shaw.ca/grubb/spamthis.html

Stephane Chazelas

unread,
Sep 18, 2006, 12:51:52 PM9/18/06
to
On Mon, 18 Sep 2006 16:37:06 +0100, SiKing wrote:
> Hi all,
>
> I was wondering if someone could lend me an explanation. :)
>
> I am working in gnu-bash, version 3.
> I have a list of commands (scripts, written in various scripting languages) in a
> text file, that my script reads in one at a time, and then I try to execute.
> What is the difference between the following ways of executing these:
> $executable
> `$executable`
> eval $executable
>
> The first and the third do what I want, but I am not sure why. The second (my
> first attempt) did not work correctly.
> Any insight is appreciated.
[...]

1 - $executable

When you leave a variable unquoted in that context (i.e. a
simple command arguments), it has a very special (and complex)
meaning.

The shell will first split the variable content into a list of
words using a complex algorithm that involves the $IFS special
variable.

With the default value of $IFS, it will split it on blanks
(discarding the leading and trailing blanks and considering a
*sequence* of blanks as a single instance of the separator).

For instance " foo<Tab> a* baz" will be split into the 3 words
"foo", "a*", "baz".

Then it expands patterns in them (a bit as it would do if you
typed them on the command line but not exactly).

So the "a*" above will be expanded into the list of files in the
current directory whose name starts with a "a".

The command to run will be derived from the first argument
resulting from that splitting, and that first argument will also
be used as the argv[0] of the command being run.

2 `$executable`

First `cmd` (aka $(cmd)), means run the cmd command, collect its
(and all its children's) output and once the command terminates
and every one of its child processes has closed its stdout (or
terminated), then use the collected output to build a list of
argument for another command, that building of arguments is done
the same way as described above for the expansion of
$executable.

For instance
`echo ls -ld -- '*.txt'`

with the default value of IFS, would collect the output of echo:
"ls -ld -- *.txt\n", remove the trailing newline, split it into
the words "ls", "-ld", "--", the list of txt files in the
current directory, would derive the "/bin/ls" command to be run
from that and would pass the /bin/ls command the list of words
above as arguments.

So

`$exectable`

would first do what is described in 1- above, then collect the
output of the command derived from the first resulting in the
splitting of $executable. And use that output to build another
list of arguments from which the first one will be used to
derive another command to be run.

3- eval $executable

$executable is split as in 1-. Except that the list of arguments
is now prepended with "eval", so the command to be run will be
"eval" instead of the first word resulting from the
splitting/wildcard expansion of $executable.

And eval concatenates its arguments with spaces and evaluates
the result as shell code.


I would say as neither of the 1, 2, 3 above is a correct way to
go. The correct way (but that depends on what $executable is
meant to contain) would be

4- eval "$executable"

Some examples.

With the default value of $IFS, with
executable='echo "ls \"foo * \""'

With 1- it will run the echo command with those arguments:
<<echo>>, <<"ls>>, <<\"foo>>, the list of files in the current
directory, <<\"">>, so will output:

"ls \"foo <the-list-of-files> \""

With 2-, it will run the same echo command, and then try and
find a command called <<"ls>> and will probably fail.

With 3-, it will run the
echo "ls \"foo <the-list-of-files> \""
command which should (unless there are shell special characters
in the list-of-files) output:

ls "foo <the-list-of-files> "

With 4-, it should run the
echo "ls \"foo * \""
command, so should output:

ls "foo * "

And eval "$(eval "$executable")" should do that and then run the
ls "foo * " command, so list the file called "foo * ".

--
Stephane

SiKing

unread,
Sep 25, 2006, 4:42:53 AM9/25/06
to

Thank You for the explanation. I had to print this out, and take it home for the
weekend. :) I also have the O'Reily "Learning bash", which I though would help
me. I was wrong.
I think I must be slow or something, because after this explanation I am still
not sure why my code works. Must be automagic or something.
What eventually helped was Unix Hater's Handbook. ;) Now on to the next challenge.

Thanx.

Rakesh Sharma

unread,
Sep 25, 2006, 6:07:09 AM9/25/06
to

Stephane Chazelas wrote:
> On Mon, 18 Sep 2006 16:37:06 +0100, SiKing wrote:

...[snipped]...

Stephane why don't u write a book on shell / unix programming. u r just
too good. your explanations are so precise, accurate, and v. good.

I think you should give this a serious thought.

Best regards,
rakesh.

SiKing

unread,
Sep 25, 2006, 11:38:28 AM9/25/06
to
SiKing wrote:
> Hi all,
>
> I was wondering if someone could lend me an explanation. :)

Yes, I am replying to my own thread, as this is more or less a rhetorical post.

I spent like three hours today coding the following function. The description
(also my own) says: Function will attempt to return a global path of whatever is
stored in variable name passed to the function. The stored path must be relative
to the _current_ position. The returned information is tested for nonsense. If
unsuccessful, then unmodified value is returned back. Note that the function
needs access to the variable name, and not the variable value -> you need to
pass the quoted name, without the $ in front! The idea is that the function is
going to be called as 'eval `globalize something`', where "something" is a
variable used by the rest of the program.
After a lot of trial and error (especially the stuff in the test), I ended up
with this:
function globalize
{
if [ -a $( eval printf ${PWD}/\${$1} ) ]
then
# convert local path to global
eval printf "$1=${PWD}/\${$1%/}\\\n"
else
# path is already global (or possibly nonsense), leave it unchanged
eval printf "$1=\${$1%/}\\\n"
fi
}
I think I should be able to get away without the printf statement inside the
test, but I am afraid to touch it after I finally got it to work.

0 new messages