Как я обрабатываю переключатели в сценарии оболочки?

Поведение утилит оболочки действительно отличается незначительными способами между вариантами Unix. Существует много вариантов Unix с комплекс история. Существуют работы по стандартизации, такие как стандарт POSIX и его надмножество Единственная спецификация UNIX. Большинство систем в наше время реализует POSIX:2001, также известный как Единственная версия 3 Спецификации UNIX, с незначительными отклонениями и многими расширениями. Единственная спецификация Unix не является учебным руководством, но версия 3 читаема, если у Вас уже есть идея того, что делает команда. Можно консультироваться с ним, чтобы знать, является ли некоторая функция стандартной или расширение конкретной системы.

Большинство пользователей UNIX использует Linux и не использовало никакой другой вариант. Linux идет с утилитами GNU, которые часто имеют много расширений стандарта. Таким образом, Вы найдете довольно много кода там, который работает над Linux, но не над другими нельдами, потому что он полагается на те расширения.

Относительно sed консультируйтесь с sed Единственной спецификацией Unix для минимума, который каждая система, как предполагается, поддерживает, страница справочника в Вашей системе для того, что Ваша поддержка внедрения и GNU sed руководство для того, что там использует большинство людей.

Одно из нестандартных расширений в GNU sed поддерживает несколько команд, выполненных вместе. Например, этот GNU sed программа печатает все строки, содержащие a, но изменения b в c во-первых:

sed -ne '/a/ {s/b/c/g; p}'

{ и } на самом деле отдельные команды, таким образом, для полной мобильности, необходимо указать их любой на отдельных строках (в файле) или в отдельном -e аргументы (на командной строке). Отсутствие разделителя команды после { и использование ; как разделитель команды общие расширения. Отсутствие разделителя команды прежде } менее общее расширение. Это стандартно-совместимо:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

Это нестандартно, но обычно принято:

sed -ne '/a/ { s/b/c/g; p; }'

Другое нестандартное, но общее расширение является использованием \n означать новую строку в a s текст замены (использование в regexp является стандартным). Портативный метод должен включать новую строку обратной косой черты в sed сценарий. Другое общее расширение \+, \? и \| в regexps для значения одного или нескольких, самое большее один и чередование; портативные основные регулярные выражения не имеют ни одного из них. Например, первая команда является непортативным способом заменить непрерывные последовательности пробела новой строкой; вторая команда является совместимым стандартами эквивалентом.

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'

17
24.01.2012, 14:09
4 ответа

Использовать getopts.

Это довольно портативно, как это находится в спецификации POSIX. К сожалению, это не поддерживает долгие опции.

См. также это getopts учебная любезность хакеров удара Wiki и этот вопрос от stackoverflow.

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

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done
16
27.01.2020, 19:46
  • 1
    Это должно быть упомянуто это getopt должен всегда проверяться как GNU getopt перед использованием его но Вы не должны использовать его так или иначе как getopts является более портативным (и обычно более хорошим), так или иначе. Если действительно необходимо назвать его по некоторым причинам, назовите его в особенном методе GNU и гарантируйте это GETOPT_COMPATIBLE не находится в среде. –  Chris Down 18.09.2011, 23:38

Я предполагаю, что Вы используете удар или подобные. Пример:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"
22
27.01.2020, 19:46
  • 1
    +1 для использования += с массивом. Не знал, что Вы могли сделать это.Мило! –  James Sneeringer 15.10.2011, 00:31

Необходимо записать цикл для парсинга параметров. Действительно можно использовать getopts команда, чтобы сделать это легко.

Это - простой пример от getopts страница руководства:

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"
5
27.01.2020, 19:46

Я недавно записал сценарий для работы, которая была универсальна и допускала несколько видов переключателей в любом порядке. Я не могу раскрыть полный сценарий по очевидным легальным причинам (не говоря уже о, у меня нет его со мной в данный момент), но вот суть его.. можно поместить его в подпрограмму и назвать его в конце сценария:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

Я действительно рекомендую ограничить Ваш сценарий удара меньше чем 400 lines/15k символами; мой вышеупомянутый сценарий вырос мимо этого размера и стал значительно трудным продолжить работать. Я начал переписывать его в Perl, который намного лучше подходит для задачи. Имейте это в виду, поскольку Вы работаете над своими сценариями в ударе. Bash является большим для маленьких сценариев и острот, но что-либо более сложное и Вы являетесь более обеспеченной записью его в Perl.

Отметьте, у меня нет тестового вышеупомянутого, таким образом, оно, вероятно, не работает, но Вы в общих чертах понимаете от него.

2
27.01.2020, 19:46
  • 1
    Путем Вы звоните options в конце не корректно, он возвратится -bash: syntax error near unexpected token $@. Назовите его как options "$@". –  Chris Down 19.09.2011, 01:46
  • 2
    Да, я перепутал Perl и Bash. Исправленный. –  laebshade 19.09.2011, 05:32
  • 3
    Это while условие не должно быть (($#)) вместо этого? –  manatwork 19.09.2011, 10:45
  • 4
    Почему Вам были бы нужны два набора круглых скобок для $#?Править: Вы правы. Прикрепленный это к while (( "$#" )) –  laebshade 20.09.2011, 03:47

Теги

Похожие вопросы