Last active
January 4, 2019 21:48
-
-
Save gene-pavlovsky/e81c8e18327540f70df4e5296ff3dd15 to your computer and use it in GitHub Desktop.
Cygwin: run a Cygwin or Windows program with pathname arguments converted to UNIX or Windows format.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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