Cygwin: run a Cygwin or Windows program with pathname arguments converted to UNIX or Windows format.
#!/bin/bash | |
# | |
# Run a program, converting UNIX and Windows format path arguments. | |
# | |
# Install in Cygwin's `bin` dir or elsewhere in your path. | |
# Create a symlink for convenience: `ln -s cygrun.sh cygrun`. | |
# | |
# Use `cygrun -w windows-program unix-path ...` to run Windows programs (e.g. from UNIX software). | |
# E.g., in my .gitconfig core.editor is set to `cygrun -w 'C:/Program Files/Notepad2/Notepad2.exe'`. | |
# | |
# Use `cygrun [-u] unix-program windows-path ...` to run Cygwin programs (e.g. from Windows software). | |
# Usually not needed since Cygwin translates Windows paths automatically (e.g. `ls 'C:\Windows'` works). | |
# Still it can be useful in case a Windows program might produce paths that mix backslashes and forward slashes, | |
# e.g. in Apache Ant `${dist.dir}/file` evaluates to `C:\path\to\project\dist/file`, which Cygwin won't | |
# translate automatically. So, to deploy the file, I use `cygrun -u scp ${dist.dir}/file ${deploy.url}`. | |
# | |
# Use the `-b` option to detach from tty, run the process in background, and return immediately. | |
# | |
# There is currently a limitation on passing non-path arguments to a program. Since there is no way | |
# to automatically distinguish path arguments from non-path arguments, all of the arguments are passed | |
# to `cygpath`. As long as non-path arguments don't contain `/` or `\` characters, and `-a` or `-C` | |
# options are not used, `cygpath` will return the arguments unmodified - no problem. | |
# Due to this, the `-a` and `-C` options are disabled at the moment. | |
# TODO: Add an option allowing to specify index positions of path arguments (comma-separated, support ranges). | |
# | |
# Most of the options are passed as is to `cygpath`, which is used for path conversion. | |
set -e -o pipefail | |
usage() { | |
local code=${1:-2} | |
test $code -ne 0 && exec >&2 | |
echo "Usage: $(basename "$0" .sh) [options] program [argument]..." | |
echo | |
echo 'Run a program, converting UNIX and Windows format path arguments.' | |
echo | |
echo 'Output type options:' | |
echo | |
echo ' -d, --dos print DOS (short) form of NAMEs (C:\PROGRA~1\)' | |
echo ' -m, --mixed like --windows, but with regular slashes (C:/WINNT)' | |
echo ' -u, --unix (default) print Unix form of NAMEs (/cygdrive/c/winnt)' | |
echo ' -w, --windows print Windows form of NAMEs (C:\WINNT)' | |
echo | |
echo 'Path conversion options:' | |
echo | |
# echo ' -a, --absolute output absolute path' | |
echo ' -U, --proc-cygdrive Emit /proc/cygdrive path instead of cygdrive prefix' | |
echo ' when converting Windows path to UNIX path.' | |
echo ' -c, --codepage CP print DOS, Windows, or mixed pathname in Windows' | |
echo ' codepage CP. CP can be a numeric codepage identifier,' | |
echo ' or one of the reserved words ANSI, OEM, or UTF8.' | |
echo ' If this option is missing, cygrun defaults to the' | |
echo ' character set defined by the current locale.' | |
echo | |
echo "Other 'cygpath' options:" | |
echo | |
echo ' -f, --file FILE read FILE for input; use - to read from STDIN' | |
echo " -o, --option read 'cygpath' options from FILE as well (for use with --file)" | |
echo ' -h, --help output usage information and exit' | |
echo | |
echo 'Run options:' | |
echo | |
# echo ' -c, --directory DIR change to directory DIR (implies -a)' | |
echo ' -b, --background run in a new session' | |
echo ' -n, --dry-run print the command that would be executed, and exit' | |
exit $code | |
} | |
run() { | |
local -n _run_args=$2 | |
if test "$dry_run"; then | |
test "$chdir" && printf 'cd %s\n' "$chdir" | |
printf '%s\n' "$1 ${_run_args[*]}" | |
else | |
test "$chdir" && cd -- "$chdir" | |
if test "$background"; then | |
setsid "$1" "${_run_args[@]}" </dev/null &>/dev/null & | |
else | |
exec "$1" "${_run_args[@]}" | |
fi | |
fi | |
} | |
declare opts fileopts chdir background dry_run | |
while test $# -gt 0; do | |
case $1 in | |
# -d|--dos|-u|--unix|-m|--mixed|-w|--windows|-a|--absolute|-U|--proc-cygdrive|-o|--option) | |
-d|--dos|-u|--unix|-m|--mixed|-w|--windows|-U|--proc-cygdrive|-o|--option) | |
opts="${opts} $1" | |
;; | |
-C|--codepage|-f|--file) | |
opts="${opts} $1 $2" | |
shift | |
;; | |
-f|--file) | |
fileopts=1 | |
opts="${opts} -i $1 $2" | |
shift | |
;; | |
# -c|--directory) | |
# shift | |
# chdir=$1 | |
# ;; | |
-b|--background) | |
background=1 | |
;; | |
-n|--dry-run) | |
dry_run=1 | |
;; | |
-h|--help) | |
usage 0 | |
;; | |
--) | |
shift | |
break | |
;; | |
-*) | |
script="$(basename "$0" .sh)" | |
echo "$script: Unknown option: $1" >&2 | |
echo "Try '$script --help' for more information." >&2 | |
exit 2 | |
;; | |
*) | |
break | |
;; | |
esac | |
shift | |
done | |
test "$chdir" && opts="$opts -a" | |
program=$1 | |
test "$program" || usage | |
shift | |
declare -a args | |
test $# -gt 0 -o "$fileopts" && mapfile -t args < <(cygpath $opts -- "$@" || exit 1) | |
run "$program" args |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment