I'm very confused about calling a command in bash with paths as parameters, coming from bash variables.
I've narrowed down the question to this:
Given a directory with the following contents:
KOSTUNRIX:i18n jand$ ls -al
total 40
drwxr-xr-x 6 jand staff 204 Mar 6 15:53 .
drwxr-xr-x 3 jand staff 102 Mar 6 10:27 ..
-rw-r--r-- 1 jand staff 3159 Mar 6 10:47 README.md
-rwxr--r-- 1 jand staff 4504 Mar 6 15:47 diff.sh
-rwxr--r-- 1 jand staff 4080 Mar 6 13:43 takeIn.sh
-rwxr--r-- 1 jand staff 558 Mar 6 15:51 test.sh
The script test.sh:
#!/bin/bash
while [[ $# -gt 1 ]]
do
key="$1"
case ${key} in
--from)
echo "--from" $2
from="$2"
shift
;;
--to)
echo "--to" $2
to="$2"
shift
;;
-c|--command)
echo "--command" $2
command="$2"
shift
;;
*)
# unknown option
echo ${key} "- huh?"
;;
esac
shift
done
pwd
echo $command
iCommand=${command/"\$from"/\"$from\"}
echo $iCommand
iCommand=${iCommand/"\$to"/\"$to\"}
echo ${iCommand}
${iCommand}
cp "./README.md" "./README.mdFORCED"
executing test.sh gives:
KOSTUNRIX:i18n jand$ ./test.sh --command "cp \$from \$to" --from ./README.md --to ./README.md2
--command cp $from $to
--from ./README.md
--to ./README.md2
[...]/i18n
cp $from $to
cp "./README.md" $to
cp "./README.md" "./README.md2"
cp: "./README.md": No such file or directory
KOSTUNRIX:i18n jand$ ls -al
total 48
drwxr-xr-x 7 jand staff 238 Mar 6 15:57 .
drwxr-xr-x 3 jand staff 102 Mar 6 10:27 ..
-rw-r--r-- 1 jand staff 3159 Mar 6 10:47 README.md
-rw-r--r-- 1 jand staff 3159 Mar 6 15:57 README.mdFORCED
-rwxr--r-- 1 jand staff 4504 Mar 6 15:47 diff.sh
-rwxr--r-- 1 jand staff 4080 Mar 6 13:43 takeIn.sh
-rwxr--r-- 1 jand staff 558 Mar 6 15:51 test.sh
After gathering the arguments (--from, --to, --command), I output for debugging:
pwd-->[...]/i18necho $command-->cp $from $toecho $iCommand-->cp "./README.md" $to(from replaced)echo $iCommand-->cp "./README.md" "./README.md2"(to replaced)
Next, I execute the last output. What bugs me is that this doesn't work. The response is:
cp: "./README.md": No such file or directory
Yet, when I copy/paste the previous string in the terminal, it works. And as a double check, I pasted a variation of that command in the script too, at the last line, and that works too, as you can see in the ls afterwards (README.mdFORCED exists).
Whatever a try with backquotes, ${}, $(), I can't get this to work.
(Note that is the simplest version of this question I came up with. The actual issue arose with doing this with paths that contain spaces -- but I gather that when this becomes clear, that might be resolved too).
Using absolute paths gives the same result:
KOSTUNRIX:i18n jand$ ./test.sh --command "cp \$from \$to" --from `pwd`/README.md --to `pwd`/README.md2
--command cp $from $to
--from /[...]/i18n/README.md
--to /[...]/i18n/README.md2
/[...]/i18n
cp $from $to
cp "/[...]/i18n/README.md" $to
cp "/[...]/i18n/README.md" "/[...]/i18n/README.md2"
cp: "/[...]/i18n/README.md": No such file or directory
Again, executing the copy/pasted command by hand
cp "/[...]/i18n/README.md" "/[...]/i18n/README.md2"
does work.
What am I missing?
pwd-->[...]/i18nboth times ([..]is the path to the directory on my disk).cperror? They aren't getting stripped. See mywiki.wooledge.org/BashFAQ/001 for why this approach (command in a string) is problematic.evalis risky to use, mywiki.wooledge.org/BashFAQ/048) and BashFAQ #50 (for best practices on programatically assembling commands, at mywiki.wooledge.org/BashFAQ/050) are more on-point than #1 (which is focused on file IO).