36

The last line in this script won't work as I expect:

myfile="afile.txt"
mycmd='cat $myfile'
eval $mycmd
echo eval $mycmd

Here echo eval $mycmd prints eval cat $myfile. How can I print eval cat afile.txt?

4 Answers 4

66

Let's take things step by step:

When you do this:

mycmd='cat $myfile'

You prevent the shell from interpolating $myfile. Thus:

$ echo $mycmd
cat $myfile

If you want to allow the interpolation, you can use double quotes:

$ mycmd="echo $myfile"  #Double quotes!
$ echo "$mycmd"
cat afile.txt

This, of course, freezes the interpretation of $mycmd when you do an eval.

$ myfile="afile.txt"
$ mycmd="echo $myfile"
$ echo $mycmd
cat afile.txt
$ eval $mycmd   #Prints out afile.txt
$ myfile=bfile.txt
$ eval $mycmd   #Still prints out afile.txt and not bfile.txt

Compare this to:

$ myfile="afile.txt"
$ mycmd='cat $myfile'   #Single quotes hide $myfile from the shell
echo $mycmd
cat $myfile             #Shell didn't change "$myfile", so it prints as a literal
$ eval $mycmd           #Prints out afile.txt
$ myfile=bfile.txt
$ eval $mycmd           #Now prints out bfile.txt

What you probably want to do is to evaluate the $mycmd in an echo statement when you echo it:

$ echo $(eval "echo $mycmd")
$ cat afile.txt
$ myfile=bfile.txt
$ echo $(eval "echo $mycmd")
cat bfile.txt
Sign up to request clarification or add additional context in comments.

2 Comments

This doesn't work for: grep fatal `find /var/log/ -name 'current'
That doesn't answer the question. From mycmd='cat $myfile' how do we get a string with cat thevalueofmyfile?!
14

You can write:

eval echo eval $mycmd

or a bit more robust:

eval echo eval "$mycmd"

That said, I'd recommend avoiding eval whenever possible; it tends to be very fragile, because there are many complicated steps in Bash command-line processing, and use of eval typically means you will perform those steps more than once. It's hard to keep track of what's really going on.

Comments

3

You need to eval the echo, rather than the other way around:

eval echo "eval $mycmd"

or

eval echo eval "$mycmd"

I think the former is preferable, but at least quote the variable expansion.

Comments

2

If you're using bash, the better way to do it is to use arrays:

myfile="afile.txt"
mycmd=(cat "$myfile")
echo "${mycmd[@]}"
"${mycmd[@]}"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.