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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.