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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.