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


1343

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

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

я получил

[: : integer expression expected

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

Ответы:


2336

Это:

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

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

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

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

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


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

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


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.

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

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

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


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».


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

}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.