比如,我有一个脚本,用这行代码调用:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
或者这个:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
什么是公认的解析方式,以便在每种情况下(或两者的某种组合)$v、$f和$d都将设置为true,而$outFile将等于/fiz/someOtherFile?
比如,我有一个脚本,用这行代码调用:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
或者这个:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
什么是公认的解析方式,以便在每种情况下(或两者的某种组合)$v、$f和$d都将设置为true,而$outFile将等于/fiz/someOtherFile?
当前回答
我使用它从末尾迭代key=>值。循环后捕获第一个可选参数。
用法为/script.sh可选的第一个参数-key value-key2 value2
#!/bin/sh
a=$(($#-1))
b=$(($#))
while [ $a -gt 0 ]; do
eval 'key="$'$a'"; value="$'$b'"'
echo "$key => $value"
b=$(($b-2))
a=$(($a-2))
done
unset a b key value
[ $(($#%2)) -ne 0 ] && echo "first_arg = $1"
当然,你可以从左到右做一些改变。
此代码段显示key=>值对和第一个参数(如果存在)。
#!/bin/sh
a=$((1+$#%2))
b=$((1+$a))
[ $(($#%2)) -ne 0 ] && echo "first_arg = $1"
while [ $a -lt $# ]; do
eval 'key="$'$a'"; value="$'$b'"'
echo "$key => $value"
b=$(($b+2))
a=$(($a+2))
done
unset a b key value
测试了100000个参数,速度很快。
您还可以从左到右迭代key=>value和第一个可选arg,而不使用eval:
#!/bin/sh
a=$(($#%2))
b=0
[ $a -eq 1 ] && echo "first_arg = $1"
for value; do
if [ $b -gt $a -a $(($b%2)) -ne $a ]; then
echo "$key => $value"
fi
key="$value"
b=$((1+$b))
done
unset a b key value
其他回答
我认为这个很简单:
#!/bin/bash
#
readopt='getopts $opts opt;rc=$?;[ "$rc$opt" = "0?" ]&&exit 1;[ $rc = 0 ]||{ shift $[OPTIND-1];false; }'
opts=vfdo:
# Enumerating options
while eval "$readopt"
do
echo OPT:$opt ${OPTARG+OPTARG:$OPTARG}
done
# Enumerating arguments
for arg
do
echo ARG:$arg
done
调用示例:
./myscript -v -do /fizz/someOtherFile -f ./foo/bar/someFile
OPT:v
OPT:d
OPT:o OPTARG:/fizz/someOtherFile
OPT:f
ARG:./foo/bar/someFile
假设我们创建一个名为test_args.sh的shell脚本,如下所示
#!/bin/sh
until [ $# -eq 0 ]
do
name=${1:1}; shift;
if [[ -z "$1" || $1 == -* ]] ; then eval "export $name=true"; else eval "export $name=$1"; shift; fi
done
echo "year=$year month=$month day=$day flag=$flag"
运行以下命令后:
sh test_args.sh -year 2017 -flag -month 12 -day 22
输出将是:
year=2017 month=12 day=22 flag=true
getopt()/getopts()是一个很好的选项。从此处复制:
“getopt”的简单用法如下小脚本所示:
#!/bin/bash
echo "Before getopt"
for i
do
echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
echo "-->$i"
done
我们所说的是,-b、 -c或-d将被允许,但-c后面跟着一个参数(“c:”表示)。如果我们称之为“g”并尝试:
bash-2.05a$ ./g -abc foo
Before getopt
-abc
foo
After getopt
-->-a
-->-b
-->-c
-->foo
-->--
我们从两个参数开始“getopt”将选项和每个人都有自己的论点。它也是添加了“--”。
# As long as there is at least one more argument, keep looping
while [[ $# -gt 0 ]]; do
key="$1"
case "$key" in
# This is a flag type option. Will catch either -f or --foo
-f|--foo)
FOO=1
;;
# Also a flag type option. Will catch either -b or --bar
-b|--bar)
BAR=1
;;
# This is an arg value type option. Will catch -o value or --output-file value
-o|--output-file)
shift # past the key and to the value
OUTPUTFILE="$1"
;;
# This is an arg=value type option. Will catch -o=value or --output-file=value
-o=*|--output-file=*)
# No need to shift here since the value is part of the same string
OUTPUTFILE="${key#*=}"
;;
*)
# Do whatever you want with extra options
echo "Unknown option '$key'"
;;
esac
# Shift after checking all the cases to get the next option
shift
done
这使您既可以使用空格分隔的选项/值,也可以使用相等的定义值。
因此,您可以使用以下命令运行脚本:
./myscript --foo -b -o /fizz/file.txt
以及:
./myscript -f --bar -o=/fizz/file.txt
并且两者应该具有相同的最终结果。
赞成的意见:
允许-arg=value和-arg-value适用于bash中可以使用的任何arg名称意思是-a或-arg或--arg或-ar-g或其他纯粹的狂欢。无需学习/使用getopt或getopts
欺骗:
无法组合参数意思是没有-abc。您必须执行-a-b-c
此示例显示了如何使用getopt和eval以及HEREDOC和shift来处理短参数和长参数,以及是否具有以下所需值。此外,switch/case语句简洁易懂。
#!/usr/bin/env bash
# usage function
function usage()
{
cat << HEREDOC
Usage: $progname [--num NUM] [--time TIME_STR] [--verbose] [--dry-run]
optional arguments:
-h, --help show this help message and exit
-n, --num NUM pass in a number
-t, --time TIME_STR pass in a time string
-v, --verbose increase the verbosity of the bash script
--dry-run do a dry run, dont change any files
HEREDOC
}
# initialize variables
progname=$(basename $0)
verbose=0
dryrun=0
num_str=
time_str=
# use getopt and store the output into $OPTS
# note the use of -o for the short options, --long for the long name options
# and a : for any option that takes a parameter
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"
while true; do
# uncomment the next line to see how shift is working
# echo "\$1:\"$1\" \$2:\"$2\""
case "$1" in
-h | --help ) usage; exit; ;;
-n | --num ) num_str="$2"; shift 2 ;;
-t | --time ) time_str="$2"; shift 2 ;;
--dry-run ) dryrun=1; shift ;;
-v | --verbose ) verbose=$((verbose + 1)); shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
if (( $verbose > 0 )); then
# print out all the parameters we read in
cat <<EOM
num=$num_str
time=$time_str
verbose=$verbose
dryrun=$dryrun
EOM
fi
# The rest of your script below
以上脚本中最重要的几行是:
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; exit 1 ; fi
eval set -- "$OPTS"
while true; do
case "$1" in
-h | --help ) usage; exit; ;;
-n | --num ) num_str="$2"; shift 2 ;;
-t | --time ) time_str="$2"; shift 2 ;;
--dry-run ) dryrun=1; shift ;;
-v | --verbose ) verbose=$((verbose + 1)); shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
简短,切中要害,可读,处理几乎所有的事情(IMHO)。
希望这对某人有所帮助。