LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   Using eval (https://www.linuxquestions.org/questions/linux-software-2/using-eval-4175426547/)

fakie_flip 09-10-2012 11:07 AM

Using eval
 
I was trying to understand exec and eval. I found this example online that claimed it would give the output of ls and df. However, it did not. Would somebody explain?

Code:

[bullshark@alpha ~]$ ./evalexample.sh
ls
df
[bullshark@alpha ~]$ cat evalexample.sh
#!/bin/bash
for i in ls df
do
    eval myvar="$i"
    echo "$myvar"
done
[bullshark@alpha ~]$


chrism01 09-10-2012 08:58 PM

This version works
Code:

#!/bin/bash
for i in ls df
do
    eval $i
done

and in fact
Code:

#!/bin/bash
for i in ls df
do
  $i
done


David the H. 09-11-2012 02:22 AM

1) Never, ever use eval unless you know exactly what you are doing. It processes the line twice, expanding variables and command substitutions on the first pass, and executing the resulting command on the second pass. This makes it very easy to insert malicious or improper code that can do damage to your system.

Eval command and security issues
http://mywiki.wooledge.org/BashFAQ/048

The bottom line: "If eval is the answer, you're almost certainly asking the wrong question".


2) exec has two uses.

First, it replaces the current process with a new one; basically switching one command for another. It allows you to do things like first run a shell, do some environment setup work, then switch over to the main program you want to run.

The second use of exec in the shell is to set up file descriptors, as described here:

http://wiki.bash-hackers.org/howto/redirection_tutorial

In short, it has nothing to do with this situation.


3)The code you posted uses a loop to first set a variable to the command names, then uses eval to "parse" the variables and execute the commands.

(Edit: actually, the OP code doesn't execute anything; the evaluated line doesn't create a command substitution environment, so eval really does nothing that the shell doesn't do anyway without it).

It's not only inefficient, non-transparent, and even dangerous, it's also completely unnecessary. Besides variables are for data, not code.

I'm trying to put a command in a variable, but the complex cases always fail!
http://mywiki.wooledge.org/BashFAQ/050

Things like this should properly be done with functions. For example:

Code:

lsdf() { ls ; df ;}        #set up a function that combines the two commands

lsdf                        #run the combined command stand-alone

myvar=$( lsdf )                #captures the combined output to $myvar

echo "$myvar"                #print the contents of the variable to the screen

This is assuming you want to do this repeatedly, of course. For a one-off command, skip the function and just capture the command output directly:

Code:

myvar=$( ls ; df )
echo "$myvar"


konsolebox 09-11-2012 02:40 AM

As another rule, it's best to always use eval with a single argument. Remember that that whole single string would be reparsed as another statement so there's no need to separate it into multiple arguments:
Code:

statement='do something radical >\"/path/$somewhere\"'
eval "$statement"

Also, never ever use eval with open variables unless on a very rare exhibition you really intend to use IFS with a different value other than whitespaces, to reparse the contents of the variable to split into multiple arguments. That would be a terrible practice though.
Code:

eval $statement
That is actually what they called evil in eval since it tends to have unexpected syntax error on runtime, but if you could see how things would happen, and know how to place things properly, it won't.

David the H. 09-11-2012 03:18 AM

Meh, let's keep it simple. Just don't use eval at all. Forget it even exists.

If you can't figure out how to do something without it, come here and let more experienced scripters help you solve it. In the very rare case it actually does require eval, we'll work out how to do it safely.

konsolebox 09-11-2012 05:08 AM

Quote:

Originally Posted by David the H. (Post 4777492)
Meh, let's keep it simple. Just don't use eval at all. Forget it even exists.

Sorry but with all respect, I'd disagree with this. You're losing a powerful utility if you do that. Learning how to use it would be better instead. There are far many things that Bash or any shell can't do without using eval, and I know that. If in doubt, I'd give you many examples if you like. There might also be other ways than using but most of the time: (a) There' similar risks with IFS-affected syntax, (b) script would run slower or inefficient, and sometimes require you more lines, and makes things difficult to read. Using externals commands most of the time decrements runtime speed. One example I had ran 20 times or 2000% slower.

David the H. 09-11-2012 11:39 AM

Of course there are uses for eval. I never said that. Nor did I say it was the only feature that carries risk. But it is one of the most serious and should never be taken lightly.

All I'm saying is, as a rule of thumb directed especially towards new scripters, if you think you need it, you are almost certainly wrong. Modern shells like bash in particular have features like associative arrays that make eval almost completely superfluous. And in those rare cases where the situation does require it, you need to be sure to do it right.

It's much safer overall for the inexperienced to simply assume up-front that they don't need it, to pretend that it doesn't exist, and ask for help when they are struggling. Let the experts judge if it's really necessary, and teach them how to do it correctly if it is. With guidance they will eventually reach a point where they are experienced enough to know what they are doing and can make their own choices, but until then, better safe than sorry.


(BTW, I can think of few things in scripting that are, by their very nature, more complex to read and use than eval. You have to write a command that creates another command, taking care to properly handle all metacharacters in the process, and it only gets worse when it includes uncontrolled variables and other substitutions. The whole thing is a nightmare of non-transparency, which is the main reason it's such a security risk.)

konsolebox 09-12-2012 12:26 AM

Quote:

Originally Posted by David the H. (Post 4777810)
Of course there are uses for eval. I never said that. Nor did I say it was the only feature that carries risk. But it is one of the most serious and should never be taken lightly.

All I'm saying is, as a rule of thumb directed especially towards new scripters, if you think you need it, you are almost certainly wrong. Modern shells like bash in particular have features like associative arrays that make eval almost completely superfluous. And in those rare cases where the situation does require it, you need to be sure to do it right.

It's much safer overall for the inexperienced to simply assume up-front that they don't need it, to pretend that it doesn't exist, and ask for help when they are struggling. Let the experts judge if it's really necessary, and teach them how to do it correctly if it is. With guidance they will eventually reach a point where they are experienced enough to know what they are doing and can make their own choices, but until then, better safe than sorry.

Well ok.

Quote:

(BTW, I can think of few things in scripting that are, by their very nature, more complex to read and use than eval. You have to write a command that creates another command, taking care to properly handle all metacharacters in the process, and it only gets worse when it includes uncontrolled variables and other substitutions. The whole thing is a nightmare of non-transparency, which is the main reason it's such a security risk.)
Well I guess it just depend on how the scripter sees it, and how he makes his script. E.g. I make scripts in a modular way, and I'm fond of using functions most of time. Anyhow I already find the scripts I make, whether eval'd, encapsulated in functions, or simplified with unusual methods, easy to read. Anyway, it seems that only examples could tell; but I no longer want to go deeper to that.

fakie_flip 09-12-2012 02:20 AM

Quote:

Originally Posted by David the H. (Post 4777462)
1) Never, ever use eval unless you know exactly what you are doing. It processes the line twice, expanding variables and command substitutions on the first pass, and executing the resulting command on the second pass. This makes it very easy to insert malicious or improper code that can do damage to your system.

Eval command and security issues
http://mywiki.wooledge.org/BashFAQ/048

The bottom line: "If eval is the answer, you're almost certainly asking the wrong question".

I'm studying for the Linux+ 2nd exam. So if I understand correctly, eval takes a variable's value and executes it as a command.


Quote:

2) exec has two uses.

First, it replaces the current process with a new one; basically switching one command for another. It allows you to do things like first run a shell, do some environment setup work, then switch over to the main program you want to run.

Current process? Would that be the terminal emulator if I launch use it interactively, and the script if non interactively? Switching which commands? And switching between programs, coming back to a main program, how would that be different than using control+z and then typing bg and later fg to get that main program back.

konsolebox 09-12-2012 03:03 AM

Quote:

Originally Posted by fakie_flip (Post 4778216)
eval takes a variable's value and executes it as a command.

Not exactly. All that eval does is re-interpret the string argument[s] that's passed on it. Double quotes ("") has its own way of evaluating its contents, and so is the command-line parser. Imagine trying to use echo instead of eval. The one that you'll see in the output is what eval would execute, in a same way if those commands are typed directly without eval. So, eval doesn't really do anything special but evaluate the contents of the arguments passed on it and run it again as another command. Please run 'help eval'. Whatever is said there is what it does, and nothing more than that.

Perhaps to make it more clear, eval is not intended to parse variables; running the command without variables would still work:
Code:

eval eval eval eval echo a


All times are GMT -5. The time now is 12:40 PM.