code / scripts

Lines748 Shell528 Python72 Lua67 Bourne Again Shell62 make15
1 others 4
Markdown4
(60 lines)
1 #!/bin/sh
2 # Simple shell script to parse one command line argument at a time.
3 #
4 # Usage: arg <flag> args...
5 #
6 # If the flag is present among the given arguments, its value (if any) will be printed.
7 # Otherwise, the command will fail (subject to the special values below).
8 # Positional arguments are those that either don't begin with a '-', or appear
9 # after a lone "--" argument.
11 # Special Values:
12 # @ Print all positional arguments (i.e. excluding flags).
13 # <num> Print the Nth positional arg, if present, otherwise fail.
14 # <flag>? Pipe output to /dev/null, but still use success status
15 # to indicate if flag is present.
16 # <flag>=<default> If flag is not present, use <default> as the value.
17 # Always succeeds.
18 # <flag1>|<flag2> If flag1 is not present, check flag2 instead.
20 # Examples:
21 # arg '-v|--verbose?' "$@" && verbose=yes || verbose=no
22 # if logfile="$(arg --log "$@")"; then ...; fi
23 # path="$(arg '-p|--path=/tmp/default' "$@")"
24 # for f in $(arg @ "$@"); do ...; done
25 # case "$(arg 1 "$@")" in ... esac
26 # arg verboten.txt'?' "$@" && echo "You can't use that file!" && exit 1
28 # Note: space-separated flag/value pairs are not supported, e.g. `ls -I \*.txt`
29 # or `ls --ignore \*.txt`. In these cases, please use the following call
30 # syntax instead: `ls -I\*.txt` or `ls -I=\*.txt` and `ls --ignore=\*.txt`.
31 # Supporting space-separated flag/value pairs would make positional argument
32 # functionality impossible because there would be no way to know whether x or y
33 # is the first positional arg in these examples: `arg 1 -f x y`, `arg 1 --foo x y`
34 # (At least, not without telling `arg` whether or not each flag expects a value)
36 # Note 2: If you expect arguments to contain "\x1E", you may want to run `arg`
37 # with a custom record separator in the environment variable `RS`. Or, if you want
38 # to customize the output of `arg @ ...` to use a custom output record separator,
39 # you can use the environment variable `ORS`.
41 [ $# -eq 0 ] && echo "arg: a single-flag argument parser. Usage: arg <flag> args..." && exit
42 target="$1"; shift
43 RS=${RS-$'\x1E'}
44 ORS=${ORS-$'\n'}
45 case "$target" in
46 @) printf "%s$RS" "$@" | awk -v RS="$RS" -v ORS="$ORS" 'raw || !/^-/; /^--$/ {raw=1}' ;;
47 --) ! printf "%s$RS" "$@" | awk -v RS="$RS" "/^--$/ {if (++count>1) exit 1}" ;;
48 -[^-]\?) ! printf "%s$RS" "$@" | awk -v RS="$RS" "/^-[^-]*${target#-}/ {exit 1}" ;;
49 *\?) $0 "${target%\?}" "$@" >/dev/null ;;
50 *=*) default="${target#*=}"; $0 "${target%%=*}" "$@" || echo "$default" ;;
51 *\|*) $0 "${target%%\|*}" "$@" || $0 "${target#*\|}" "$@" ;;
52 [1-9]*) n="$target"; [ $# -ge "$n" ] && ORS="$RS" $0 @ "$@" | awk -v RS="$RS" "NR==$n" ;;
53 -[^-]) ! printf "%s$RS" "$@" | awk -v RS="$RS" "
54 /^--$/ {exit 0}
55 /^-[^-]*${target#-}/ {sub(/^-[^-]*${target#-}=?/,\"\"); print; exit 1}" ;;
56 *) ! printf "%s$RS" "$@" | awk -v RS="$RS" "
57 /^--$/ {exit 0}
58 /^$target$/ {exit 1}
59 /^$target=/ {sub(/^$target=/,\"\"); print; exit 1}" ;;
60 esac