I have a parent script

while read cmd 
  nohup ./script ${cmd[@]} &>> log &
done < ~/list 

that executes this child script

while true
  eval "${CMD[@]}"

with this list of commands

node ~/www/splash/app.js
node ~/www/splash-two/app.js

When the child script calls eval ${CMD[@]} it executes the way I expect running that command with no complaints but when I try to remove the eval and run the command using ${CMD[@]} it throws the error:

Error: Cannot find module '/home/rumplefraggle/SYS/RABBOT/~/www/splash/app.js'

Now I thought possibly this had something to do with the node command so I tried to execute
ls ~
as the command and it throws the error that ~ can not be found.

Echoing ${@} and not running it expands as I would expect it to.

Also manually inserting the command into the child script also works as expected

I don't understand why eval works and simply running the command using ${@} does not. What is causing ${@} to not expand the ~?

Why is node appending the directory name to the command when ${@} is used?

  • 2
    by the way: read cmd reads an entire line as a single string, and assigns that string to cmd. So it makes little sense to use ${cmd[@]}; cmd is not an array, so you might as well just use $cmd. If you want read to read into an array, use read -a. Also, you almost always want read -r. help read for more info.
    – rici
    Jul 9, 2013 at 18:26

2 Answers 2


This is because of tilde expansion. The eval expands the tilde, which is replaced with the full path to the home directory. Without it, the command gets a literal tilde passed, and tries to use a relative path (that doesn't exist).

$ echo ~
$ echo "~" 
$ eval 'echo ~' 
  • Didn't you mean eval 'echo ~' or eval "echo ~"? Or even eval echo "~"? As typed, it will produce output ~
    – rici
    Jul 9, 2013 at 18:21
  • I see and the error is reporting the full path! Its not actually the command being executed just an artifact in the error report. I need to dig more into the expansion and why it expands in eval an not on the path Jul 9, 2013 at 19:04
  • @rici Thanks, my bad, I was typing this out from my phone.
    – Chris Down
    Jul 10, 2013 at 3:37

You need quotes: "${cmd[@]}"

Without the quotes, all the elements of the array are smushed up into a single string. With quotes, each element will be properly handled individually.

From the manual:

If the subscript is ‘@’ or ‘*’, the word expands to all members of the array name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, [...] ${name[@]} expands each element of name to a separate word.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .