Разбор аргументов сценария оболочки

18

Есть несколько вопросов по поводу такого рода вещей, но давайте представим, что мы нацелены на общую систему Linux с установленными и getopt, и getopts (не то, что мы будем использовать также, но они кажутся популярными)

Как мне проанализировать как длинные (--example | --example simple-option), так и короткие аргументы (-e | -esimple-example | -e simple-example)

    
задан Peter Coulton 15.04.2010 в 06:22
источник

1 ответ

33

Вы хотите использовать getopt с длинными и короткими опциями. Пример из рабочего кода:

# Parse arguments
TEMP=$(getopt -n $PROGRAM_NAME -o p:P:cCkhnvVS \
--long domain-password:,pop3-password:\         
,create,cron,kill,help,no-sync-passwords,version,verbose,skip-pop3 \
-- "[email protected]")                                                            

# Die if they fat finger arguments, this program will be run as root
[ $? = 0 ] || die "Error parsing arguments. Try $PROGRAM_NAME --help"       

eval set -- "$TEMP"
while true; do     
        case $1 in 
                -c|--create)
                        MODE="CREATE"; shift; continue
                ;;                                    
                -C|--cron)                            
                        MODE="CRON"; shift; continue  
                ;;                                    
                -k|--kill)                            
                        MODE="KILL"; shift; continue  
                ;;                                    
                -h|--help)                            
                        usage                         
                        exit 0                        
                ;;                                    
                -n|--no-sync-passwords)               
                        SYNC_VHOST=0; shift; continue 
                ;;                                    
                -p|--domain-password)                 
                        DOMAIN_PASS="$2"; shift; shift; continue
                ;;                                              
                -P|--pop3-password)                             
                        POP3_PASS="$2"; shift; shift; continue  
                ;;                                              
                -v|--version)                                   
                        printf "%s, version %s\n" "$PROGRAM_NAME" "$PROGRAM_VERSION"
                        exit 0                                                      
                ;;                                                                  
                -v|--verbose)                                                       
                        VERBOSE=1; shift; continue                                  
                ;;                                                                  
                -S|--skip-pop3)                                                     
                        SKIP_POP=1; shift; continue                                 
                ;;                                                                  
                --)                                                                 
                        # no more arguments to parse                                
                        break                                                       
                ;;                                                                  
                *)                                                                  
                        printf "Unknown option %s\n" "$1"                           
                        exit 1                                                      
                ;;                                                                  
        esac                                                                        
done     

Примечание. die - это функция, которая была определена ранее (не показана).

Опция -n указывает getopt сообщать об ошибках как имя моей программы, а не как getopt . -o определяет список коротких опций ( : после опции указывает необходимый аргумент), а --long указывает список длинных опций (соответствующих по порядку коротким опциям).

Остальное - простой переключатель, вызывающий shift соответствующим образом для продвижения указателя аргумента. Обратите внимание, что вызывать shift; shift; - просто сложная привычка. В современном мире, вероятно, будет достаточно shift 2 .

Современный getopt довольно совместим с более новыми платформами, однако вы можете столкнуться с некоторыми проблемами переносимости на старых (около Redhat 9) системах. Смотрите man getopt для информации о обратной совместимости. Однако вряд ли вы столкнетесь с необходимостью.

Наконец, после анализа параметров вы можете еще раз позвонить:

eval set -- "[email protected]"

Это переместит указатель аргумента на все остальное, что осталось в командной строке после того, как getopt выполнит параметры синтаксического анализа. Затем вы можете просто shift , чтобы продолжать читать их. Например, если команда выглядела так:

./foo --option bar file1.txt file2.txt file3.txt

Не забудьте сделать удобную опцию -h / --help , чтобы распечатать новые необычные опции, как только вы закончите. :) Если вы сделаете этот вывод help2man дружественным, у вас будет мгновенная страница справочника, чтобы перейти с вашим новым инструментом.

Edit

В большинстве дистрибутивов вы можете найти больше примеров кода getopt в /usr/share/doc/util-linux/examples , который должен быть установлен по умолчанию.

    
ответ дан Tim Post 15.04.2010 в 09:47
  • Я действительно понимаю, что я не делаю никакого здравомыслия здесь, чтобы проверить наличие нескольких команд, устанавливающих MODE. В этом случае было приемлемо, что последний вариант просто имел приоритет, а паста предназначалась только для информации об одном способе использования getopt. –  Tim Post♦ 15.04.2010 в 09:55
  • Я уже упоминался с использованием getopt () несколько раз. Назовите меня глупым, но я просто не могу понять, как это работает. Поскольку для моего скрипта необходим эквивалент Windows, я использовал это. На мой взгляд, это гораздо более чистый и менее волшебный подход. Могу ли я сделать что-то подобное на linux? –  Christian 21.10.2012 в 11:46
  • @Christian Вы могли бы что-то подобное с BASH,% 1 став $ 1 (и $ 2 соответственно, если $ 1 ожидает аргумент). Фактически, многие люди просто делают это таким образом, продолжайте циклически перемещаться по аргументам через смену и запускать текущий аргумент через коммутатор. getopt просто обрабатывает все это волшебство, плюс обязательный анализ аргументов для вас, поэтому многим нравится это удобство. –  Tim Post♦ 21.10.2012 в 13:21
  • Спасибо Тим. Я понимаю, почему getop лучше, я просто не мог понять, как он работает менее чем за 10 минут, что для моей задачи слишком много по сравнению с простым переводом 1: 1. Кроме того, при одновременном выполнении обоих сценариев один и тот же шаблон кода упрощает его поддержку. Во всяком случае, спасибо за понимание этого. –  Christian 21.10.2012 в 14:25