2

In Python, if a string represents a statement, to execute it we have to use eval.

In Bash, why is it not the same case?

$ cmd="ls"
$ $cmd
 a.out  company.png
Tim
  • 101,790
  • 1
    Because is different language. And how do you expect script to exec -rwxrwxr-x or 1 or ben? – Romeo Ninov Nov 20 '18 at 19:56
  • eval does exist in bash, though its use is often discouraged. It does in fact execute a string as if the string was typed on the command line. See man bash. What you're showing is executing something stored in an array, not a string, so I'm not sure what you're asking. – Kevin Kruse Nov 20 '18 at 19:59
  • @KevinKruse I simplify my example to use variable instead of array. I am trying to see why I don't need eval to run a string as a command in bash, while I do in python. – Tim Nov 20 '18 at 20:03
  • 1
    @Ben because if I had to type eval before every command I typed into my shell, I would switch to a different shell. ;) Bash and Python serve different purposes, so their usage and syntax are different. After redirection, variable expansion, etc. anything on the command prompt is treated as a command. – Kevin Kruse Nov 20 '18 at 20:16

1 Answers1

3

Python and Bash are entirely different languages. The main purpose of Python is to execute internal statements with the added capability to execute external programs. The main purpose of the shell is to execute external programs, with some control structures and internal commands added. Bash has more internal features than the original shell, but still maintains compatibility.

One of the features of the shell is that you can define variables and have them later expanded in commands. Basically you can think that the shell implicitly uses something like Python's eval for each statement, although there are of course differences.

There is also an eval command to the shell that can be useful and dangerous if the normal level of processing and substitution isn't enough and you need an additional level. It evaluates the rest of the line and feeds the result to the normal substitutions the shell performs. Until you have a better understanding and an actual need for it, it's best to forget about this feature.

RalfFriedl
  • 8,981
  • Thanks. I found that when cmd=( "ls" "|" "cat") "${cmd[@]}" doesn't run by itself, but need eval "${cmd[@]}". cmd="ls | cat" also need eval "$cmd". So when do I need eval and when do I not need eval to run a string or an array of strings as a command? – Tim Nov 20 '18 at 21:45
  • When will using eval fail to run a command while not using eval will succeed? – Tim Nov 20 '18 at 21:48
  • 1
    You need eval if the replacement string contains a shell special symbol, like ;, &, |, $, and you want it to have its special meaning instead of using it literally. Succeeding without eval depends on the definition of "succeed". Commands with special characters will behave differently, although you may consider them to succeed in both cases. – RalfFriedl Nov 20 '18 at 23:05
  • Thanks. Here is an example of using eval with failure: https://unix.stackexchange.com/questions/483015/how-can-i-output-nul-correctly-to-a-file-via-a-script. Can I use eval and succeed? – Tim Nov 20 '18 at 23:07
  • You can always add more quotes to preserve the meaning of special characters. – RalfFriedl Nov 20 '18 at 23:10
  • Is adding more quotes an input-specific approach? In eval "${cmd[@]}" > "$FILE", no matter how many quotes I add to it, will it always succeed for some ${cmd[@]}, but fail for some other ${cmd[@]}? In other ways, can one always construct some ${cmd[@]} for it to fail? – Tim Nov 20 '18 at 23:12
  • Do you have any particular problem? If the question is about the nul bytes in the substitution, I don't think there is a way to do that, and I'm not sure why that would be useful. Maybe it's best to ask a new question, or modify that question to include why you want nul bytes. Maybe there is a better way to achieve what you want. – RalfFriedl Nov 20 '18 at 23:17