research を数日経っても、.shスクリプトでcmdline引数を解析するための最良の方法がまだわかりません。私の参考文献によると、getoptsコマンドは、位置パラメータ変数を乱すことなく、「スイッチを抽出してチェックするため、進むべき道です。予期しないスイッチ、または引数がないスイッチは、エラーとして認識され、報告されます。」
位置パラメータ(例2-$ @、$#など)は、スペースが含まれている場合は明らかにうまく機能しませんが、通常の長いパラメータ(-pおよび--longparam)を認識できます。ネストされた引用符でパラメーターを渡すと、両方のメソッドが失敗することに気付きました(「これは、「引用符」の例です。」)。これらの3つのコードサンプルのうち、どれがcmdline引数を処理する方法を最もよく示していますか? getopt関数はgurusによって推奨されていないため、回避しようとしています!
例1:
#!/bin/bash
for i in "$@"
do
case $i in
-p=*|--prefix=*)
PREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
-s=*|--searchpath=*)
SEARCHPATH=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
-l=*|--lib=*)
DIR=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
;;
--default)
DEFAULT=YES
;;
*)
# unknown option
;;
esac
done
exit 0
例2:
#!/bin/bash
echo ‘number of arguments’
echo "\$#: $#"
echo ”
echo ‘using $num’
echo "\$0: $0"
if [ $# -ge 1 ];then echo "\$1: $1"; fi
if [ $# -ge 2 ];then echo "\$2: $2"; fi
if [ $# -ge 3 ];then echo "\$3: $3"; fi
if [ $# -ge 4 ];then echo "\$4: $4"; fi
if [ $# -ge 5 ];then echo "\$5: $5"; fi
echo ”
echo ‘using $@’
let i=1
for x in $@; do
echo "$i: $x"
let i=$i+1
done
echo ”
echo ‘using $*’
let i=1
for x in $*; do
echo "$i: $x"
let i=$i+1
done
echo ”
let i=1
echo ‘using shift’
while [ $# -gt 0 ]
do
echo "$i: $1"
let i=$i+1
shift
done
[/bash]
output:
bash> commandLineArguments.bash
number of arguments
$#: 0
using $num
$0: ./commandLineArguments.bash
using $@
using $*
using shift
#bash> commandLineArguments.bash "abc def" g h i j*
例3:
#!/bin/bash
while getopts ":a:" opt; do
case $opt in
a)
echo "-a was triggered, Parameter: $OPTARG" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
exit 0
getopt
の使用が最も簡単だと思います。それはそうでなければトリッキーである引数の正しい処理を提供します。たとえば、getopt
は、コマンドラインで--arg=option
または--arg option
として指定された長いオプションの引数を処理する方法を知っています。
シェルスクリプトに渡された入力の解析に役立つのは、"$@"
変数の使用です。これと$@
の違いについては、bashのmanページをご覧ください。これにより、スペースを含む引数を処理できるようになります。
簡単なコマンドライン引数を解析するためのスクリプトを作成する方法の例を次に示します。
#!/bin/bash
args=$(getopt -l "searchpath:" -o "s:h" -- "$@")
eval set -- "$args"
while [ $# -ge 1 ]; do
case "$1" in
--)
# No more options left.
shift
break
;;
-s|--searchpath)
searchpath="$2"
shift
;;
-h)
echo "Display some help"
exit 0
;;
esac
shift
done
echo "searchpath: $searchpath"
echo "remaining args: $*"
このように使用して、スペースと引用符が保持されることを示します。
user@machine:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"."
searchpath: File with spaces and "quotes".
remaining args: other args
getopt
の使用に関するいくつかの基本的な情報を見つけることができます here
getopt
の使用を避けたい場合は、このすばやいアプローチを使用できます。
##
コメントとして定義します(必要に応じてカスタマイズします)。log.sh
#!/bin/sh
## $PROG 1.0 - Print logs [2017-10-01]
## Compatible with bash and dash/POSIX
##
## Usage: $PROG [OPTION...] [COMMAND]...
## Options:
## -i, --log-info Set log level to info (default)
## -q, --log-quiet Set log level to quiet
## -l, --log MESSAGE Log a message
## Commands:
## -h, --help Displays this help and exists
## -v, --version Displays output version and exists
## Examples:
## $PROG -i myscrip-simple.sh > myscript-full.sh
## $PROG -r myscrip-full.sh > myscript-simple.sh
PROG=${0##*/}
LOG=info
die() { echo $@ >&2; exit 2; }
log_info() {
LOG=info
}
log_quiet() {
LOG=quiet
}
log() {
[ $LOG = info ] && echo "$1"; return 1 ## number of args used
}
help() {
grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0
}
version() {
help | head -1
}
[ $# = 0 ] && help
while [ $# -gt 0 ]; do
CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" log.sh | sed -e "s/-/_/g")
if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi
shift; eval "$CMD" $@ || shift $? 2> /dev/null
done
このコマンドを実行する:
./log.sh --log yep --log-quiet -l nop -i -l yes
この出力を生成します:
yep
yes
ところで:posix と互換性があります!