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

1343

Мне нужно проверить наличие входного аргумента. У меня есть следующий скрипт

if [ "$1" -gt "-1" ]
  then echo hi
fi

я получил

[: : integer expression expected

Как сначала проверить входной аргумент1, чтобы увидеть, существует ли он?

user775187
источник

Ответы:

2336

Это:

if [ $# -eq 0 ]
  then
    echo "No arguments supplied"
fi

$#Переменное покажет вам количество входных аргументов был принят сценарий.

Или вы можете проверить, является ли аргумент пустой строкой или нет:

if [ -z "$1" ]
  then
    echo "No argument supplied"
fi

-zКоммутатор будет проверять , если расширение «$ 1» пустая строка или нет. Если это пустая строка, то тело выполняется.

phoxis
источник
62
Мне нравится делать это таким образом, с кратким синтаксисом и все еще приемлемым POSIX. [ -z "$1" ] && echo "No argument supplied" Я предпочитаю однострочники, так как они легче для меня; и это также быстрее проверить выходное значение, по сравнению с использованиемif
JM Becker
168
Возможно, вы захотите добавить exit 1в конце вашего эха внутри блока if, когда для работы скрипта необходим аргумент. Очевидно, но стоит отметить полноту.
MSANFORD
16
Вполне возможно, хотя и редко полезно, чтобы первый аргумент был инициализирован, но пуст; programname "" secondarg third, $#Проверка однозначно проверяет количество аргументов.
tripleee
39
Для новичка, особенно для человека, не имеющего опыта работы с сценариями, также важно упомянуть некоторые особенности этих вещей. Вы могли бы также упомянуть, что нам нужен пробел после открывающей и закрывающей скобок. В противном случае вещи не работают. Я сам Noob сценария (я из C фона) и нашел его трудным путем. Только когда я решил скопировать все как есть, все сработало для меня. Тогда я понял, что должен оставить пробел после открывающей скобки и до закрывающей.
HighOnMeat 13.09.13
72
и для необязательных аргументовif [ ! -z "$1" ]; then ...
gcb
347

Лучше продемонстрировать этот способ

if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 1
fi

Обычно вам нужно выйти, если у вас слишком мало аргументов.

Val
источник
72
Нет, это не так: это то, exit 1что вы обычно хотите, и использует [[ ]]тест, который (iirc) обычно более разумен. Так что для людей, слепо копирующих код, это лучший ответ.
dshepherd
42
Чтобы более знать о разнице между [] и [[]] см stackoverflow.com/questions/3427872/...
Себастьян Grignoli
104

В некоторых случаях вам нужно проверить, передал ли пользователь аргумент скрипту, и если нет, вернуться к значению по умолчанию. Как в сценарии ниже:

scale=${2:-1}
emulator @$1 -scale $scale

Здесь, если пользователь не передал scaleвторой параметр, я запускаю эмулятор Android -scale 1по умолчанию. ${varname:-word}является оператором расширения. Есть и другие операторы расширения:

  • ${varname:=word}который устанавливает неопределенное значение varnameвместо возврата wordзначения;
  • ${varname:?message}который либо возвращает значение, varnameесли оно определено и не равно нулю, либо печатает messageи прерывает скрипт (как в первом примере);
  • ${varname:+word}который возвращает wordтолько если varnameон определен и не равен нулю; возвращает ноль в противном случае.
Алекс Н.
источник
1
Пример выше, кажется, использовать ${varname?message}. Это дополнительная :опечатка, или это меняет поведение?
Eki
6
Эки, «:» - это встроенная команда и сокращение для / bin / true в этом примере. Она представляет собой команду «ничего не делать», которая в основном игнорирует аргументы, которые она предоставляет. Это важно в этом тесте, чтобы не дать интерпретатору попытаться выполнить содержимое «$ varname» (что вы, конечно, НЕ хотите, чтобы это произошло). Также стоит отметить; с помощью этого метода вы можете протестировать столько переменных, сколько пожелаете. И все с конкретными сообщениями об ошибках. т.е.: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
user.friendly
48

Пытаться:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi
Ранджиткумар Т
источник
4
Зачем вам нужны двойные кавычки для $#и 0?
user13107 12.12.14
1
Нет проблем, если мы используем без двойных кавычек, таких как $ # и 0
Ranjithkumar T
на Windows, MINGW это единственный путь.
Лайош Месарос
2
Этот ответ является отличной отправной точкой для только что написанного сценария. Спасибо за показ elseтоже.
Крис К,
2
@ user13107 Переменные в двойных кавычках в bash предотвращают сбои (т. е. расширение имен файлов, например foo*) и разбиение слов (т. е. разбиение содержимого, если значение содержит пробел). В этом случае нет необходимости цитировать, $#потому что оба из этих случаев не применяются. Заключение в 0кавычки также не обязательно, но некоторые люди предпочитают заключать в кавычки значения, так как они действительно являются строками, и это делает его более явным
Деннис
39

Другой способ определить, были ли аргументы переданы в скрипт:

((!$#)) && echo No arguments supplied!

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

Чтобы выйти при отсутствии каких-либо аргументов, можно сказать:

((!$#)) && echo No arguments supplied! && exit 1

Другой (аналогичный) способ сказать выше было бы:

let $# || echo No arguments supplied

let $# || { echo No arguments supplied; exit 1; }  # Exit if no arguments!

help let говорит:

let: let arg [arg ...]

  Evaluate arithmetic expressions.

  ...

  Exit Status:
  If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
devnull
источник
2
-1 это может быть наихудший метод при проверке существования аргумента ... плюс он может вызвать подстановку истории и потенциально может привести к ошибкам.
user.friendly
2
вместо того, exitчто убивает мой процесс Zsh, я использую, returnкоторый не убивает его
Тимо
Зачем ((!$#))вызывать подмену истории?
Жро
25

Я часто использую этот фрагмент для простых сценариев:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi
f2cx
источник
1
Значит, для этого нужно использовать только один аргумент?
Даниэль
21

Только потому, что есть еще одна базовая точка, которую я хочу указать, я добавлю, что вы можете просто проверить, что ваша строка пуста:

if [ "$1" ]; then
  echo yes
else
  echo no
fi

Аналогично, если вы ожидаете, что arg count, просто проверьте ваш последний:

if [ "$3" ]; then
  echo has args correct or not
else
  echo fixme
fi

и так далее с любым аргументом или вар

seorphates
источник
4

Если вы хотите проверить, существует ли аргумент, вы можете проверить, является ли число аргументов большим или равным вашему целевому номеру аргумента.

Следующий скрипт демонстрирует, как это работает

test.sh

#!/usr/bin/env bash

if [ $# -ge 3 ]
then
  echo script has at least 3 arguments
fi

производит следующий вывод

$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments
Брэд Паркс
источник
3

В качестве небольшого напоминания, числовые операторы тестирования в Bash работают только с целыми числами ( -eq, -lt, -geи т.д.)

Я хотел бы убедиться, что мои $ Vars являются целыми

var=$(( var + 0 ))

прежде чем проверять их, просто для защиты от ошибки «[: integer arg required».

Cwissy
источник
1
Неплохой трюк, но, пожалуйста, обратите внимание: из-за неспособности bash обрабатывать числа с плавающей точкой в ​​арифметике этот метод может вызвать синтаксическую ошибку и вернуть ненулевое значение, что будет помехой, если включен errexit. var=$(printf "%.0f" "$var")может обрабатывать числа с плавающей точкой, но страдает от ненулевого выхода при задании строки. Если вы не возражаете в AWK, это я использую метод представляется наиболее надежным для обеспечения соблюдения целого числа: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Если переменная не установлена, по умолчанию используется значение «0». Если var - это число с плавающей точкой, оно округляется до ближайшего целого числа. Отрицательные значения также можно использовать.
user.friendly
0

валидация одной строки

myFunction() {

    : ${1?"forgot to supply an argument"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

добавить имя функции и использование

myFunction() {

    : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

добавить проверку, чтобы проверить, является ли целое число

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

: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"

затем создайте функцию проверки, которая проверяет аргумент, возвращая 0 в случае успеха, 1 в случае неудачи и функцию die, которая прерывает скрипт в случае неудачи

validateIntegers() {

    if ! [[ "$1" =~ ^[0-9]+$ ]]; then
        return 1 # failure
    fi
    return 0 #success

}

die() { echo "$*" 1>&2 ; exit 1; }

Еще проще - просто используйте set -u

set -u гарантирует, что каждая ссылочная переменная установлена ​​при ее использовании, поэтому просто установите ее и забудьте

myFunction() {
    set -u
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}
AndrewD
источник