Проверьте количество аргументов, переданных скрипту Bash

432

Я хочу, чтобы мой Bash script печатал сообщение об ошибке, если счетчик требуемых аргументов не выполняется.

Я попробовал следующий код:

#!/bin/bash
echo Script name: $0
echo $# arguments 
if [$# -ne 1]; 
    then echo "illegal number of parameters"
fi

По какой-то неизвестной причине у меня есть следующая ошибка:

test: line 4: [2: command not found

Что я делаю неправильно?

  • 42
    Вы не должны называть свой сценарий test . Это название стандартной команды Unix, вы бы не хотели ее скрывать.
  • 14
    Всегда используйте пробелы вокруг '[' ('[[') или '(' ('((')) в операторах if в bash.
Показать ещё 6 комментариев
Теги:
parameter-passing

7 ответов

619
Лучший ответ

Как и любая другая простая команда, [ ... ] или test требуют пробелов между его аргументами.

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters"
fi

или

if test "$#" -ne 1; then
    echo "Illegal number of parameters"
fi

В Bash предпочитайте вместо этого использовать [[ ]], поскольку он не выполняет разделение слов и расширение имени пути к своим переменным, что цитирование может не понадобиться, если оно не является частью выражения.

[[ $# -ne 1 ]]

Он также имеет некоторые другие функции, такие как группировка без кавычек, сопоставление шаблонов (расширенное сопоставление образцов с extglob) и сопоставление регулярных выражений.

В следующем примере проверяется правильность аргументов. Он допускает один аргумент или два.

[[ ($# -eq 1 || ($# -eq 2 && $2 == <glob pattern>)) && $1 =~ <regex pattern> ]]

Для чистых арифметических выражений использование (( )) для некоторых может все же быть лучше, но они все еще возможны в [[ ]] с его арифметическими операторами, такими как -eq, -ne, -lt, -le, -gt или -ge, поместив выражение как один строковый аргумент:

A=1
[[ 'A + 1' -eq 2 ]] && echo true  ## Prints true.

Это должно быть полезно, если вам нужно будет объединить его с другими функциями [[ ]].

Ссылки:

48

Это может быть хорошей идеей использовать арифметические выражения, если вы имеете дело с числами.

if (( $# != 1 )); then
    echo "Illegal number of parameters"
fi
26

В []:! =, =, ==... являются операторами сравнения строк и -eq, -gt... являются арифметическими двоичными.

Я бы использовал:

if [ "$#" != "1" ]; then

Или:

if [ $# -eq 1 ]; then
  • 8
    == на самом деле не документировано, что случается работать с GNU test . Случается также работать с FreeBSD test , но не может работать на Foo test . Единственное стандартное сравнение - = (только к вашему сведению).
  • 1
    Это описано в записи bash man: Когда используются операторы == и! =, Строка справа от оператора считается шаблоном и сопоставляется в соответствии с правилами, описанными ниже в разделе «Сопоставление с шаблоном». Если включена опция оболочки nocasematch, сопоставление выполняется без учета буквенных символов. Возвращаемое значение равно 0, если строка соответствует (==) или не соответствует (! =) Шаблону, и 1 в противном случае. Любая часть шаблона может быть заключена в кавычки, чтобы ее можно было сопоставить как строку.
Показать ещё 1 комментарий
21

Если вас интересует только bailing, если отсутствует какой-либо аргумент, Замена параметров великолепна:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT
  • 0
    разве это не загружено с помощью ударов?
  • 0
    @DwightSpencer Это будет иметь значение?
Показать ещё 2 комментария
10

Простой один лайнер, который работает, может быть выполнен с использованием:

[ "$#" -ne 1 ] && ( usage && exit 1 ) || main

Это разбивается на:

  • проверить переменную bash для размера параметров $# не равна 1 (наш номер подкоманд)
  • если true, тогда функция use() вызова и выход со статусом 1
  • else вызов функции main()

Думает заметить:

  • use() может быть просто эхом "$ 0: params"
  • main может быть длинным script
  • 1
    Если у вас есть другой набор строк после этой строки, это было бы неправильно, поскольку exit 1 будет применяться только к контексту подоболочки, делая его просто синонимом ( usage; false ) . Я не являюсь поклонником такого упрощения, когда дело доходит до разбора опций, но вы можете использовать { usage && exit 1; } вместо. Или, возможно, просто { usage; exit 1; }
  • 1
    @konsolebox (использование && выход 1) работает для ksh, zsh и bash, возвращаясь к bash 2.0. Синтаксис {...} недавно появился в 4.0+ в bash. Не поймите меня неправильно, если для вас работает один из способов, используйте его, но помните, что не все используют ту же реализацию bash, что и вы, и мы должны написать код, чтобы установить стандарты, а не bashisms.
Показать ещё 1 комментарий
0

Если вы хотите быть в безопасности, я рекомендую использовать getopts.

Вот небольшой пример:

    while getopts "x:c" opt; do
      case $opt in
        c)
          echo "-$opt was triggered, deploy to ci account" >&2
          DEPLOY_CI_ACCT="true"
          ;;
            x)
              echo "-$opt was triggered, Parameter: $OPTARG" >&2 
              CMD_TO_EXEC=${OPTARG}
              ;;
            \?)
              echo "Invalid option: -$OPTARG" >&2 
              Usage
              exit 1
              ;;
            :)
              echo "Option -$OPTARG requires an argument." >&2 
              Usage
              exit 1
              ;;
          esac
        done

подробнее см. здесь http://wiki.bash-hackers.org/howto/getopts_tutorial

0

Вы должны добавить пробелы между условиями теста:

if [ $# -ne 1 ]; 
    then echo "illegal number of parameters"
fi

Надеюсь, это поможет.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню