How to pass arguments with spaces to MinGW-MSYS shell scripts from the Windows command line? - windows

I have a sh script, myscript.sh, which takes a directory as an input argument and does some recursive processing of the files in that directory. I want to run this script in Windows command line (I use the MinGW/MSYS distribution).
How do I properly provide a path with spaces as an input argument?
For example, I want to give a path, 'dirA\dir B'. I tried many different combinations, including
sh -c 'myscript.sh "dirA/dir B"'
sh -c 'myscript.sh "dirA/dir\ B"'
sh -c "myscript.sh 'dirA/dir\\ B'"
sh -c "myscript.sh \"dirA/dir B\" "
sh -c "myscript.sh dirA/dir\ B "
But on all of them the script understands the path as 'dirA/dir'.

cmd doesn't understand single quotes. If sh does, then make the outer quotes double, so that you're double-quoting the argument at the cmd prompt, and passing the single quotes to sh to interpret.
The third option you listed is the right idea, but it's not clear to me what you're doing with the \\. Does sh require you to escape the space within a double-quoted string? If I'm not mistaken, it's either/or, not both. One of these should work (depending on whether your sh Windows port uses Unix-style forward slash path separators or Windows-style backslash separators or both):
sh -c "myscript.sh 'dirA/dir B'"
or
sh -c "myscript.sh 'dirA\dir B'"
I'm not sure why the fourth option doesn't work. That method works fine for passing double-quoted arguments to PowerShell from cmd. For example, this works:
powershell -noexit "sl \"C:\Program Files\""
This leads me to suspect that it's sh that's having a problem with the path arguments 'dirA/dir B' and "dirA/dir B" -- especially if the suggestions above don't work.
Speaking of PowerShell, you might want to give that a try instead. Any of the following should work:
sh -c 'myscript.sh "dirA/dir B"'
sh -c "myscript.sh 'dirA/dir B'"
sh -c 'myscript.sh ''dirA/dir B'''
sh -c "myscript.sh `"dirA/dir B`""

Related

Why getting blank output when running "/bin/sh" with "-c" option [duplicate]

This question already has answers here:
How to use positional parameters with "bash -c" command?
(2 answers)
Closed 14 days ago.
I am running /bin/sh with -c option as below but getting a blank output:
[root#dockerhost dproj]# /bin/sh -c echo helloworld
[root#dockerhost dproj]#
Why the above command is not printing helloworld?
I have tried to read the man page but not able to understand anything.
From man sh:
-c Read commands from the command_string operand.
Set the value of special parameter 0
(see Section 2.5.2, Special Parameters) from the
value of the command_name operand and the positional
parameters ($1, $2, and so on) in sequence from the
remaining argument operands.
No commands shall be read from the standard input.
/bin/sh -c echo helloworld runs the command echo, which prints a blank line. You meant to type:
/bin/sh -c "echo helloworld"
which runs the command echo helloworld.
The -c option to sh causes the first non-option argument to be treated as a string of commands to run in a new shell. The remaining arguments are used to fill in the that shell's numbered arguments, starting with $0 (the "name" under which the shell process is running.) These arguments are not automatically parsed to any utility executed by that shell.
So if you invoke sh with /bin/sh -c echo helloworld:
the input passed to the shell interpreter sh is simply echo
helloworld becomes $0 in the sh session.
Normally, $0 in a shell invocation should be the name of the shell; that's what it will be set to by default:
bash$ /bin/sh
$ echo $0
/bin/sh
$ exit
bash$ echo $0
bash
Since the command given to the shell by -c is interpreted as though it were input to the shell itself, you can use $n in the command in order to refer to the extra arguments to the shell interpreter. If you want to do that, you need to remember to single-quote the -c option argument so that it's contents are not interpreted by the outer shell. Perhaps studying the following will help:
bash$ /bin/sh -c 'echo $0' fakename # Correctly single-quoted
fakename
bash$ /bin/sh -c "echo $0" fakename # Here, $0 is expanded by the outer shell
bash
bash$ /bin/sh -c 'echo "$#"' sh arg1 arg2 arg3 # $0 is not part of $#
arg1 arg2 arg3

Does semicolon split multiple commands in double quoted string?

The command
cd /tmp; echo Hello
generates
Hello
Quoted, the command
"cd /tmp; echo Hello"
generates
-bash: cd /tmp; echo Hello: No such file or directory
Any idea why this is so? I am trying to use the quotes so I can build up a command chain and pass it through ssh on to a remote host. Thank you.
Quotes don't define strings; they define words, so in this case your command consists of exactly one word (containing lots of whitespace in addition to a ;). The first (non-assignment) word on a command line is treated as the name of the command, resulting in the error you see.
ssh works differently because the entire string is passed to a second shell on the remote end to be evaluated again. Just like you can run sh -c "cd /tmp; echo hello" on your local host, the following two commands are roughly equivalent:
ssh host "cd /tmp; echo hello"
ssh host sh -c "cd /tmp; echo hello"
Semicolon sign interpreted literally inside double quotes.
More explanation can't be found here https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html

Bash: Execute command WITH ARGUMENTS in new terminal [duplicate]

This question already has answers here:
how do i start commands in new terminals in BASH script
(2 answers)
Closed 20 days ago.
So i want to open a new terminal in bash and execute a command with arguments.
As long as I only take something like ls as command it works fine, but when I take something like route -n , so a command with arguments, it doesnt work.
The code:
gnome-terminal --window-with-profile=Bash -e whoami #WORKS
gnome-terminal --window-with-profile=Bash -e route -n #DOESNT WORK
I already tried putting "" around the command and all that but it still doesnt work
You can start a new terminal with a command using the following:
gnome-terminal --window-with-profile=Bash -- \
bash -c "<command>"
To continue the terminal with the normal bash profile, add exec bash:
gnome-terminal --window-with-profile=Bash -- \
bash -c "<command>; exec bash"
Here's how to create a Here document and pass it as the command:
cmd="$(printf '%s\n' 'wc -w <<-EOF
First line of Here document.
Second line.
The output of this command will be '15'.
EOF' 'exec bash')"
xterm -e bash -c "${cmd}"
To open a new terminal and run an initial command with a script, add the following in a script:
nohup xterm -e bash -c "$(printf '%s\nexec bash' "$*")" &>/dev/null &
When $* is quoted, it expands the arguments to a single word, with each separated by the first character of IFS. nohup and &>/dev/null & are used only to allow the terminal to run in the background.
Try this:
gnome-terminal --window-with-profile=Bash -e 'bash -c "route -n; read"'
The final read prevents the window from closing after execution of the previous commands. It will close when you press a key.
If you want to experience headaches, you can try with more quote nesting:
gnome-terminal --window-with-profile=Bash \
-e 'bash -c "route -n; read -p '"'Press a key...'"'"'
(In the following examples there is no final read. Let’s suppose we fixed that in the profile.)
If you want to print an empty line and enjoy multi-level escaping too:
gnome-terminal --window-with-profile=Bash \
-e 'bash -c "printf \\\\n; route -n"'
The same, with another quoting style:
gnome-terminal --window-with-profile=Bash \
-e 'bash -c '\''printf "\n"; route -n'\'
Variables are expanded in double quotes, not single quotes, so if you want them expanded you need to ensure that the outermost quotes are double:
command='printf "\n"; route -n'
gnome-terminal --window-with-profile=Bash \
-e "bash -c '$command'"
Quoting can become really complex. When you need something more advanced that a simple couple of commands, it is advisable to write an independent shell script with all the readable, parametrized code you need, save it somewhere, say /home/user/bin/mycommand, and then invoke it simply as
gnome-terminal --window-with-profile=Bash -e /home/user/bin/mycommand

parenthesis in a directory name in bash script

I get the error executing bash syntax error near unexpected token `('
I know the error is caused by the ')' but I thought placing the commands in-between ' ' is suppose to allow the parenthesis in a directory name. How can I fix this without renaming the name?
bash -c 'cd /tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.0000
0sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg) && exec bash xfade.sh'
please note:
It's being called from inside octave a math program like matlab
Why are you bothering with an outer shell? Quote the argument to cd:
(cd '/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)' && exec bash xfade.sh)
If you really must use an extra bash -c...
dirname='/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)'
bash -c 'cd "$1" && exec bash xfade.sh' _ "$dirname"
Can you use double quotes for bash -c?
bash -c "cd '/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)' && exec bash xfade.sh"
You need to quote the path inside of the command string passed to the bash subshell. E.g.:
bash -c 'cd '"'"'/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg) && exec bash xfade.sh'"'"''
You get the error because running bash -c passes the argument string to a new shell. The argument string will have the single quotes stripped by the outer (invoking) shell.
UPDATED: to correctly quote single quotes inside single quotes as pointed out by Charles Duffy

Escape backquote in a double-quoted string in shell

For the command: /usr/bin/sh -c "ls 1`" (a backquote after 1).
How to make it run successfully? Adding a backslash before "`" does not work.
` is a special char as we know, and I tried surrounding it with single quote too (/usr/bin/sh -c "ls 1'`'"), but that doesn't work either.
The error always are:
% /usr/bin/sh -c "ls 1\`"
Unmatched `
You need to escape the backtick, but also escape the backslash:
$ touch 1\`
$ /bin/sh -c "ls 1\\\`"
1`
The reason you have to escape it "twice" is because you're entering this command in an environment (such as a shell script) that interprets the double-quoted string once. It then gets interpreted again by the subshell.
You could also avoid the double-quotes, and thus avoid the first interpretation:
$ /bin/sh -c 'ls 1\`'
1`
Another way is to store the filename in a variable, and use that value:
$ export F='1`'
$ printenv F
1`
$ /bin/sh -c 'ls $F' # note that /bin/sh interprets $F, not my current shell
1`
And finally, what you tried will work on some shells (I'm using bash, as for the above examples), just apparently not with your shell:
$ /bin/sh -c "ls 1'\`'"
1`
$ csh # enter csh, the next line is executed in that environment
% /bin/sh -c "ls 1'\`'"
Unmatched `.
I strongly suggest you avoid such filenames in the first place.
Use single quotes instead:
/usr/bin/sh -c 'ls 1\`'
/usr/bin/sh -c "ls '1\`'"

Resources