Reputation: 103
How do I invoke a batch file from a bash script under Cygwin, with...
where...
I have a windows batch script C:\Program Files (x86)\bin\script.bat, which takes a (windows) path to an input file as argument - example:
@ECHO OFF
echo "This is script.bat. The value of the first argument is [%~1]"
I want to redirect the output of script.bat into an output file at another absolute path.
On the windows command prompt (cmd.exe), I would invoke the command like this:
C:\> "C:\Program Files (x86)\bin\script.bat" "C:\Input Path\input.txt" > "C:\Output Path\output.txt"
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
I can omit the double quotes around the script and the redirection target if I apply "batch-style escaping", but that doesn't work for the argument (for some reason):
C:\> C:\Program^ Files^ ^(x86^)\bin\script.bat "C:\Input Path\input.txt" > C:\Output^ Path\output.txt
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
...but:
C:\> C:\Program^ Files^ ^(x86^)\bin\script.bat C:\Input^ Path\input.txt > C:\Output^ Path\output.txt
output.txt: This is script.bat. The value of the first argument is [C:\Input].
I can also wrap the command into an additional call to cmd.exe, using additional double quotes around the whole term:
C:\> cmd.exe /C ""C:\Program Files (x86)\bin\script.bat" "C:\Input Path\input.txt" > "C:\Output Path\output.txt""
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
C:\> cmd.exe /C "C:\Program^ Files^ ^(x86^)\bin\script.bat "C:\Input Path\input.txt" > C:\Output^ Path\output.txt"
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
I can also apply the output redirection to the outer cmd.exe instance:
C:\> cmd.exe /C ""C:\Program Files (x86)\bin\script.bat" "C:\Input Path\input.txt"" > "C:\Output Path\output.txt"
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
C:\> cmd.exe /C "C:\Program^ Files^ ^(x86^)\bin\script.bat "C:\Input Path\input.txt"" > C:\Output^ Path\output.txt
output.txt: This is script.bat. The value of the first argument is [C:\Input Path\input.txt].
So far so good. But how can I invoke any of the above command lines from a bash script under Cygwin?
All paths initially exist only in Unix format:
#!/bin/sh
BIN_UNIX="/cygdrive/c/Program Files (x86)/bin/script.bat"
ARG_UNIX="/cygdrive/c/Input Path/input.txt"
OUT_UNIX="/cygdrive/c/Output Path/output.txt"
Note that the file $OUT_UNIX does not exist at the time the script is called (so 'cygpath --dos ...' doesn't work).
I have experimented with dozens of more or less clumsy combinations of Unix / Windows paths (converting with cygpath), no quotes, single quotes, double quotes, no escaping, "bash-style" escaping, "batch-style" escaping, etc. The only working solution I could find depends on an 8.3-style path for the batch script, which eliminates white spaces and special characters:
#!/bin/sh
# [...]
BIN_DOS=$( cygpath --dos "${BIN_UNIX}" )
ARG_WIN=$( cygpath --windows "${ARG_UNIX}" )
cmd /C "${BIN_DOS}" "${ARG_WIN}" > "$OUT_UNIX"
But there must be a more systematic and robust way to do this, right?
Related questions which all don't fully answer my question:
Why is it that Cygwin can run .bat scripts?
Windows batches in Cygwin with spaces in path and arguments
correct quoting for cmd.exe for multiple arguments
How to Pass Command Line Parameters with space in Batch File
Upvotes: 1
Views: 659
Reputation: 82420
You could use
BIN_WIN=$( cygpath --windows "${BIN_UNIX}" )
ARG_WIN=$( cygpath --windows "${ARG_UNIX}" )
OUT_WIN=$( cygpath --windows "${OUT_UNIX}" )
cmd /c CALL "$BIN_WIN" "${ARG_WIN}" > "$OUT_WIN"
The important point is the CALL
in front of your command.
cmd /c
fails to start a command with spaces inside, because it splits the command even when there are quotes around.
The cmd /c
would also work without CALL
, but with additional enclosing quotes.
cmd /c " "C:\Program Files (x86)\bin\script.bat" "args" "
But it seems to be impossible to transfer raw quotes from cygwin to cmd.exe
, because cygwin translates quotes to \"
, so the expression becomes
cmd /c \" "C:\Program Files (x86)\bin\script.bat" "args" \"
Upvotes: 3