Shell脚本:混合getopts与位置参数可能吗?
我想devise一个shell脚本作为几个脚本的包装。 我想使用getopts
为myshell.sh
指定参数, myshell.sh
其余参数以相同的顺序传递给指定的脚本。
如果执行myshell.sh
,如下所示:
myshell.sh -h hostname -s test.sh -d waittime param1 param2 param3 myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh myshell.sh param1 -h hostname -d waittime -s test.sh param2 param3
以上所有应该可以称为
test.sh param1 param2 param3
是否可以利用 myshell.sh
的选项参数 并将其余参数发布到底层脚本中?
对不起,对一个旧线程发表评论,但认为我会为那些正在寻找如何做到这一点的人发布信息…
我想做一些类似于OP的事情,我在这里和这里find了我需要的相关信息
本质上,如果你想做的事情如:
script.sh [options] ARG1 ARG2
然后让你的select是这样的:
while getopts "h:u:p:d:" flag; do case "$flag" in h) HOSTNAME=$OPTARG;; u) USERNAME=$OPTARG;; p) PASSWORD=$OPTARG;; d) DATABASE=$OPTARG;; esac done
然后你可以得到你的位置参数是这样的:
ARG1=${@:$OPTIND:1} ARG2=${@:$OPTIND+1:1}
更多的信息和细节可以通过上面的链接。
希望帮助!
getopts
不会分析param1
和-n
选项的组合。
将param1-3与其他选项放在一起是更好的select。
此外,你可以使用已经存在的库,如shflags 。 这是非常聪明的,它很容易使用。
最后一种方法是编写你自己的函数来parsingparams,而不是getopts,只是遍历所有的参数。 这是最难的方法,但它是唯一正确匹配您的期望的方法。
[编辑:修正了两个错别字]
我想到了getopts
可以扩展到真正混合选项和位置参数的一种方法。 这个想法是在调用getopts
和分配任何发现的位置参数n1
, n2
, n3
等之间交替:
parse_args() { _parse_args 1 "$@" } _parse_args() { local n="$1" shift local options_func="$1" shift local OPTIND "$options_func" "$@" shift $(( OPTIND - 1 )) if [ $# -gt 0 ]; then eval test -n \${n$n+x} if [ $? -eq 0 ]; then eval n$n="\$1" fi shift _parse_args $(( n + 1 )) "$options_func" "$@" fi }
那么在OP的情况下,你可以像这样使用它:
main() { local n1='' n2='' n3='' local duration hostname script parse_args parse_main_options "$@" echo "n1 = $n1" echo "n2 = $n2" echo "n3 = $n3" echo "duration = $duration" echo "hostname = $hostname" echo "script = $script" } parse_main_options() { while getopts d:h:s: opt; do case "$opt" in d) duration="$OPTARG" ;; h) hostname="$OPTARG" ;; s) script="$OPTARG" ;; esac done } main "$@"
运行它显示输出:
$ myshell.sh param1 param2 -h hostname param3 -d waittime -s test.sh n1 = param1 n2 = param2 n3 = param3 duration = waittime hostname = hostname script = test.sh
只是一个概念的certificate,但也许这对某个人有用。
注意:如果一个使用parse_args
函数调用另一个使用parse_args
函数, 而外部函数声明例如local n4=''
,但是内部的函数不会传递4个或更多的位置参数给内部函数
刚刚把一个quickie变成了一个quickie,它很容易处理一个选项和位置参数的混合(在$ @中只保留位置参数):
#!/bin/bash while [ ${#} -gt 0 ];do OPTERR=0;OPTIND=1;getopts "p:o:hvu" arg;case "$arg" in p) echo "Path: [$OPTARG]" ;; o) echo "Output: [$OPTARG]" ;; h) echo "Help" ;; v) echo "Version" ;; \?) SET+=("$1") ;; *) echo "Coding error: '-$arg' is not handled by case">&2 ;; esac;shift;[ "" != "$OPTARG" ] && shift;done [ ${#SET[@]} -gt 0 ] && set "" "${SET[@]}" && shift echo -e "=========\nLeftover (positional) parameters (count=$#) are:" for i in `seq $#`;do echo -e "\t$i> [${!i}]";done
示例输出:
[root@hots:~]$ ./test.sh 'aa bb' -h -v -u -q 'cc dd' -p 'ee ff' 'gg hh' -o ooo Help Version Coding error: '-u' is not handled by case Path: [ee ff] Output: [ooo] ========= Leftover (positional) parameters (count=4) are: 1> [aa bb] 2> [-q] 3> [cc dd] 4> [gg hh] [root@hots:~]$
混合select和参数:
ARGS="" echo "options :" while [ $# -gt 0 ] do unset OPTIND unset OPTARG while getopts as:c: options do case $options in a) echo "option a no optarg" ;; s) serveur="$OPTARG" echo "option s = $serveur" ;; c) cible="$OPTARG" echo "option c = $cible" ;; esac done shift $((OPTIND-1)) ARGS="${ARGS} $1 " shift done echo "ARGS : $ARGS" exit 1
结果:
bash test.sh -a arg1 arg2 -s serveur -c cible arg3 options : option a no optarg option s = serveur option c = cible ARGS : arg1 arg2 arg3
对于unix选项处理有一些标准,在shell编程中, getopts
是强制执行它们的最好方法。 几乎所有现代语言(perl,python)在getopts
上都有一个变体。
这只是一个简单的例子:
command [ options ] [--] [ words ]
-
每个选项必须以短划线开始,
-
必须由单个字符组成。 -
GNU项目引入了Long Options,以两个破折号开头,后面跟着一个单词
--long_option
。 AST KSH项目有一个getopts,它也支持长选项, 而长选项以单个破折号开始-
如find(1)
。 -
期权可能会或可能不会期望论据。
-
任何不以短划线开始的单词,都将结束选项处理。
-
string
--
必须被跳过,并将结束选项处理。 -
任何剩余的参数保留为位置参数。
Open Group有一个关于Utility Argument Syntax
的部分
Eric Raymond的“Unix编程艺术” 有一章介绍了选项字母及其含义的传统unixselect。
你可以试试这个技巧:在使用optargs循环之后,使用这个片段
#shift away all the options so that only positional agruments #remain in $@ for (( i=0; i<OPTIND-1; i++)); do shift done POSITIONAL="$@"
但是,这种方法有一个错误:
- 在第一个位置参数之后的所有选项都由getopts进行存储,并被视为位置参数 – 事件是正确的(请参阅示例输出:-m和-c在位置参数中)
也许它有更多的错误…
看整个例子:
while getopts :abc opt; do case $opt in a) echo found: -a ;; b) echo found: -b ;; c) echo found: -c ;; \?) echo found bad option: -$OPTARG ;; esac done #OPTIND-1 now points to the first arguments not beginning with - #shift away all the options so that only positional agruments #remain in $@ for (( i=0; i<OPTIND-1; i++)); do shift done POSITIONAL="$@" echo "positional: $POSITIONAL"
输出:
[root@host ~]# ./abc.sh -abc -de -fgh -bca haha blabla -m -c found: -a found: -b found: -c found bad option: -d found bad option: -e found bad option: -f found bad option: -g found bad option: -h found: -b found: -c found: -a positional: haha blabla -m -c