Перевірте наявність аргументу введення в сценарії оболонки 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.