Sprawdź istnienie argumentu wejściowego w skrypcie powłoki Bash


1335

Muszę sprawdzić istnienie argumentu wejściowego. Mam następujący skrypt

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

dostaję

[: : integer expression expected

Jak najpierw sprawdzić argument wejściowy 1, aby sprawdzić, czy istnieje?

Odpowiedzi:


2328

To jest:

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

$#Zmienna powie liczbę wejściowych argumentów skrypt została podjęta.

Lub możesz sprawdzić, czy argument jest pustym łańcuchem, czy nie:

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

-zPrzełącznik będzie sprawdzić, czy ekspansja „$ 1” jest ciągiem null lub nie. Jeśli jest to łańcuch zerowy, ciało jest wykonywane.


62
Lubię to robić w ten sposób, w zwięzłej składni i wciąż akceptowalnej przez POSIX. [ -z "$1" ] && echo "No argument supplied" Wolę jednowarstwowe, ponieważ są dla mnie łatwiejsze; a także szybciej sprawdzić wartość wyjścia, w porównaniu do używaniaif
JM Becker

168
Prawdopodobnie chcesz dodać exit 1na końcu swojego echa wewnątrz bloku if, gdy wymagany jest argument do działania skryptu. Oczywiste, ale warte odnotowania dla kompletności.
msanford,

16
Możliwe jest, choć rzadko przydatne, zainicjowanie pierwszego argumentu, ale puste; programname "" secondarg third. $#Check jednoznacznie sprawdza liczbę argumentów.
tripleee

39
W przypadku nooba, zwłaszcza osoby wywodzącej się ze środowisk niezwiązanych ze skryptami, ważne jest również, aby wspomnieć o pewnych osobliwościach dotyczących tych rzeczy. Mógłbyś także wspomnieć, że potrzebujemy miejsca po klamrze otwierającej i zamykającej. W przeciwnym razie rzeczy nie działają. Sam jestem skryptem noob (pochodzę z języka C) i znalazłem to na własnej skórze. Dopiero kiedy zdecydowałem się skopiować całość „tak jak jest”, wszystko zadziałało dla mnie. Wtedy zdałem sobie sprawę, że muszę zostawić miejsce po nawiasie otwierającym, a przed zamykającym.
HighOnMeat

72
i dla opcjonalnych argumentówif [ ! -z "$1" ]; then ...
gcb

346

Lepiej to zademonstrować w ten sposób

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

Zwykle musisz wyjść, jeśli masz za mało argumentów.


72
Nie, to nie jest: ma to, exit 1co zwykle chcesz, i wykorzystuje [[ ]]test, który (iirc) jest zwykle bardziej rozsądny. Więc dla osób ślepo kopiujących i wklejających kod jest to lepsza odpowiedź.
dshepherd

42
Aby dowiedzieć się więcej o różnicy między [] a [[]], zobacz stackoverflow.com/questions/3427872/...
Sebastián Grignoli

103

W niektórych przypadkach musisz sprawdzić, czy użytkownik przekazał argument do skryptu, a jeśli nie, powróć do wartości domyślnej. Jak w skrypcie poniżej:

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

Tutaj, jeśli użytkownik nie przeszedł scalejako drugi parametr, -scale 1domyślnie uruchamiam emulator Androida . ${varname:-word}jest operatorem ekspansji. Istnieją również inne operatory ekspansji:

  • ${varname:=word}która ustawia niezdefiniowane varnamezamiast zwracać wordwartość;
  • ${varname:?message}który albo zwraca, varnamejeśli jest zdefiniowany i nie ma wartości null, albo wypisuje messageskrypt i przerywa skrypt (jak w pierwszym przykładzie);
  • ${varname:+word}który zwraca wordtylko jeśli varnamejest zdefiniowany i nie jest pusty; w przeciwnym razie zwraca null.

1
Powyższy przykład wydaje się używać ${varname?message}. Czy dodatkowa :literówka czy to zmienia zachowanie?
Eki

6
Eki, „:” jest wbudowanym poleceniem i skrótem dla / bin / true w tym przykładzie. Reprezentuje polecenie „nic nie rób”, które zasadniczo ignoruje podane argumenty. Jest to niezbędne w tym teście, aby powstrzymać tłumacza przed próbą wykonania zawartości „$ varname” (czego na pewno NIE chcesz się wydarzyć). Warto również zauważyć; tą metodą możesz przetestować dowolną liczbę zmiennych. A wszystko to z określonymi komunikatami o błędach. tj.: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
user.friendly

48

Próbować:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi

4
Dlaczego potrzebujesz podwójnych cudzysłowów dla $#i 0?
user13107,

1
Nie ma problemu, jeśli używamy bez podwójnych cudzysłowów, takich jak $ # i 0
Ranjithkumar T

w Windows, mingw to jedyna droga.
Lajos Meszaros,

2
Ta odpowiedź stanowi świetny punkt wyjścia do skryptu, który właśnie stworzyłem. Dzięki za pokazanie else.
Chris K

2
@ user13107 zmienne podwójnie cytowane w bash zapobiegają globowaniu (tj. rozszerzaniu nazw plików itp. foo*) i dzieleniu słów (tj. dzieleniu zawartości, jeśli wartość zawiera białe spacje). W takim przypadku nie ma potrzeby cytowania, $#ponieważ oba te przypadki nie mają zastosowania. Cytowanie 0również nie jest konieczne, ale niektórzy ludzie wolą cytować wartości, ponieważ są one naprawdę ciągami znaków, co czyni je bardziej wyraźnymi.
Dennis

39

Innym sposobem na wykrycie, czy argumenty zostały przekazane do skryptu:

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

Zauważ, że (( expr ))powoduje to, że wyrażenie jest oceniane zgodnie z regułami arytmetyki powłoki .

Aby wyjść bez jakichkolwiek argumentów, można powiedzieć:

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

Innym (analogicznym) sposobem stwierdzenia powyższego byłoby:

let $# || echo No arguments supplied

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

help let mówi:

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 może to być najgorsza metoda, jeśli sprawdzanie poprawności istnienia argumentu .. plus może wyzwalać podstawianie historii i potencjalnie robić złe rzeczy.
user.friendly

2
zamiast tego, exitktóry zabija mój proces zsh, używam tego, returnco go nie zabija
Timo,

Po co ((!$#))uruchamiać podstawianie historii?
Zhro

25

Często używam tego fragmentu kodu do prostych skryptów:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi

1
Więc to ma być użyte, gdy potrzebujesz tylko jednego argumentu?
Danijel

21

Tylko dlatego, że jest więcej punktów bazowych do podkreślenia, dodam, że możesz po prostu przetestować swój ciąg znaków: null:

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

Podobnie, jeśli oczekujesz liczby argów, po prostu przetestuj swój ostatni:

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

i tak dalej z dowolnym arg lub var


4

Jeśli chcesz sprawdzić, czy argument istnieje, możesz sprawdzić, czy liczba argumentów jest większa lub równa docelowej liczbie argumentów.

Poniższy skrypt pokazuje, jak to działa

test.sh

#!/usr/bin/env bash

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

produkuje następujące dane wyjściowe

$ ./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

Jako mały Przypominamy, że operatorzy testy numeryczne w bash działa tylko na liczby całkowite ( -eq, -lt, -ge, itd.)

Chciałbym upewnić się, że moje $ vars są ints

var=$(( var + 0 ))

przed ich przetestowaniem, tylko w celu obrony przed błędem „[: liczba całkowita wymagana”.


1
Zgrabna sztuczka, ale uwaga: z powodu niemożności basha obsługi operacji zmiennoprzecinkowych w arytmetyce, ta metoda może powodować błąd składniowy i zwracać wartość niezerową, co byłoby przeszkodą w włączeniu errexitu. var=$(printf "%.0f" "$var")może obsługiwać zmiennoprzecinkowe, ale otrzymuje ciąg niezerowy po otrzymaniu ciągu. Jeśli nie przeszkadza ci awk ta metoda używam wydaje się być najbardziej wytrzymałe egzekwowania liczbę całkowitą: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Jeśli var nie jest ustawione, domyślnie jest ustawione na „0”. Jeśli var jest liczbą zmiennoprzecinkową, jest zaokrąglana do najbliższej liczby całkowitej. Można również użyć wartości ujemnych.
user.friendly

0

walidacja funkcji bash liniowej

myFunction() {

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

}

dodaj nazwę funkcji i użycie

myFunction() {

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

}

dodaj sprawdzanie poprawności, aby sprawdzić, czy liczba całkowita

aby dodać dodatkowe sprawdzanie poprawności, na przykład aby sprawdzić, czy przekazany argument jest liczbą całkowitą, zmodyfikuj jeden wiersz sprawdzania poprawności, aby wywołać funkcję sprawdzania poprawności:

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

następnie skonstruuj funkcję sprawdzania poprawności, która sprawdza poprawność argumentu, zwracając 0 w przypadku sukcesu, 1 w przypadku niepowodzenia i funkcję die, która przerywa skrypt w przypadku niepowodzenia

validateIntegers() {

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

}

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

Jeszcze prościej - po prostu użyj set -u

set -u upewnia się, że każda zmienna, do której istnieje odwołanie, jest ustawiona, gdy jest używana, więc po prostu ustaw ją i zapomnij

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

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.