2013-02-09 4 views
9

После нескольких дней research я до сих пор не могу найти лучший метод для разбора cmdline args в сценарии .sh. По моим ссылкам на getopts ЦМДЕ является путем, так как он «экстрактов и проверяют переключатели, не нарушая позиционный параметр variables.Unexpected выключатели или переключатели, которые отсутствуют аргументы, распознается и reportedas ошибки.»Лучший способ разбора командной строки args в Bash?

Позиционных params (Пример 2 - $ @, $ # и т. д.), по-видимому, не работают хорошо, когда задействованы пробелы, но могут распознавать регулярные и длинные параметры (-p и --longparam). Я заметил, что оба метода терпят неудачу при передаче параметров с вложенными кавычками («это Ex. Of» «quotes» «.»). Какой из этих трех примеров кода лучше всего иллюстрирует способ работы с аргументами cmdline? Функция getopt не рекомендуется гуру, поэтому я стараюсь ее избегать!

Пример 1:

#!/bin/bash 
for i in "[email protected]" 
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 [email protected]’ 
let i=1 
for x in [email protected]; 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 [email protected] 

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 
+1

Возможный дубликат [Как проанализировать аргументы командной строки в bash?] (Http://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash) –

ответ

18

я найти применение getopt будет самым простым. Он обеспечивает правильную обработку аргументов, которые в противном случае сложны. Например, getopt будет знать, как обрабатывать аргументы в длинной опции, указанной в командной строке, как --arg=option или --arg option.

Что полезно при разборе любого ввода, переданного скрипту оболочки, является использование переменных "[email protected]". См. Справочную страницу bash о том, как это отличается от [email protected]. Это гарантирует, что вы можете обрабатывать аргументы, содержащие пробелы.

Вот пример того, как я мог бы написать ей сценарий, чтобы разобрать некоторые простые аргументы командной строки:

#!/bin/bash 

args=$(getopt -l "searchpath:" -o "s:h" -- "[email protected]") 

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: $*" 

и использовали, как это, чтобы показать, что пробелы и кавычки сохраняются:

[email protected]:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"." 
searchpath: File with spaces and "quotes". 
remaining args: other args 

Некоторые базовую информацию об использовании getopt можно найти here

+2

Это хороший пример Getopt Austin. Эта особая тема широко обсуждалась в [stackoverflow] (http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line- опции/7680682 # 7680682). Разница в том, что простой старый getopt не так прочен, как getopts, и не работает на старых системах. Getopts может анализировать длинные коммутаторы так же, как есть короткая версия одного и того же коммутатора, поэтому для этого требуется небольшая настройка. Я буду придерживаться w/getopts. Я предпочитаю использовать встроенную функцию вместо старого exec (getopt) для профессиональных скриптов. – LogicalConfusion

0

Если вы хотите избежать использования getopt, вы можете n используйте этот хороший быстрый подход:
- Определение справки по всем параметрам в виде ## comments (настройте по своему усмотрению);
- Определяет для каждой опции функцию с тем же именем;
- Скопируйте последние пять строк этого скрипта на ваш скрипт (магия).

Пример: журнал.ш

#!/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 [email protected] >&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#--}(?:[= ])" go.sh | sed -e "s/-/_/g") 
    if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi 
    shift; eval "$CMD" [email protected] || shift $? 2> /dev/null 
done 

Тестирование:

./log.sh --log yep --log-quiet -l nop -i -l yes будет производить:

yep 
yes 

Кстати: Она совместима с POSIX!