Перевірте наявність аргументу введення в сценарії оболонки Bash


1336

Мені потрібно перевірити наявність вхідного аргументу. У мене є наступний сценарій

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

я отримав

[: : integer expression expected

Як перевірити спочатку вхідний аргумент1, щоб побачити, чи існує він?

Відповіді:


2328

Це є:

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. $#Перевірка однозначно перевіряє кількість аргументів.
трійчатка

39
Для нобу, особливо того, хто походить з не-сценарію, також важливо згадати деякі особливості щодо цих речей. Ви могли б також зазначити, що нам потрібен пробіл після відкриття та фіксації. Інакше все не працює. Я сам сценарій нуб (я родом із C) і вважаю, що це важкий шлях. Лише тоді, коли я вирішив скопіювати всю річ «як є», мені працювали речі. Саме тоді я зрозумів, що мені потрібно залишити місце після вступної дужки і перед закриттям.
HighOnMeat

72
а для необов'язкових if [ ! -z "$1" ]; then ...
аргів

346

Краще продемонструвати таким чином

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

Зазвичай вам потрібно вийти, якщо у вас занадто мало аргументів.


72
Ні, це не так: це exit 1зазвичай є те, що ви хочете, і використовує [[ ]]тест, який (iirc), як правило, більш розумний. Тож для людей, які сліпо копіюють кодування, це краща відповідь.
dshepherd

42
Щоб більш знати про різницю між [] і [[]] см stackoverflow.com/questions/3427872 / ...
Себастьян Grignoli

103

У деяких випадках потрібно перевірити, чи передав користувач аргумент сценарію, а якщо ні, повернутися до значення за замовчуванням. Як у сценарії нижче:

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визначено і не є нульовим; повертає null в іншому випадку.

1
Наведений приклад, здається, використовує ${varname?message}. Це зайва :помилка, чи це змінює поведінку?
Екі

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?
користувач13107

1
Немає проблем, якщо ми використовуємо без подвійних лапок, як $ # і 0
Ranjithkumar T

на windows, mingw - це єдиний шлях.
Лайош Мецарос

2
Ця відповідь дає чудову відправну точку для щойно створеного сценарію. Дякуємо за те, що показали elseтеж.
Кріс К

2
@ user13107 змінні з подвійним цитуванням в bash запобігають поширенню (тобто розширенню назви файлів, як foo*) і розбиттю слів (тобто розщепленню вмісту, якщо значення містить пробіл). У цьому випадку цитувати це не обов’язково, $#оскільки обидва ці випадки не застосовуються. Цитування циферблатів 0також не є необхідним, але деякі люди вважають за краще цитувати значення, оскільки вони дійсно є рядками, і це робить його більш чітким.
Денніс

39

Ще один спосіб визначити, чи були передані аргументи до сценарію:

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

Зауважте, що (( expr ))змушує вираз оцінюватись за правилами арифметики Shell .

Для того, щоб вийти за відсутності аргументів, можна сказати:

((!$#)) && 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

Так само якщо ви очікуєте, що кількість аргументів просто перевіряйте останню:

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 потрібно".


1
Акуратний трюк, але зауважте: через нездатність bash обробляти плавці в арифметиці, цей метод може викликати синтаксичну помилку і повернути не нульове значення, що буде перешкодою, коли помилка errexit включена. var=$(printf "%.0f" "$var")може обробляти поплавці, але страждає від ненульового виходу, коли дається рядок. Якщо ви не заперечуєте в AWK, це я використовую метод є найбільш надійним для забезпечення дотримання цілого числа: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Якщо var не встановлено, він за замовчуванням встановлений на "0". Якщо var - float, він округляється до найближчого цілого числа. Негативні значення також чудово використовувати.
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.