Controlla l'esistenza dell'argomento di input in uno script della shell Bash


1340

Devo verificare l'esistenza di un argomento di input. Ho il seguente script

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

ottengo

[: : integer expression expected

Come controllo prima l'argomento input1 per vedere se esiste?

Risposte:


2332

È:

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

La $#variabile ti dirà il numero di argomenti di input che lo script è stato passato.

Oppure puoi verificare se un argomento è una stringa vuota o meno:

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

Lo -zswitch verificherà se l'espansione di "$ 1" è una stringa nulla o meno. Se è una stringa nulla, il corpo viene eseguito.


62
Mi piace farlo in questo modo, in sintassi concisa e ancora accettabile POSIX. [ -z "$1" ] && echo "No argument supplied" Preferisco i liner singoli, poiché sono più facili per me; ed è anche più veloce controllare il valore di uscita, rispetto all'utilizzoif
JM Becker

168
Probabilmente vuoi aggiungere un exit 1alla fine del tuo echos all'interno del blocco if quando è richiesto l'argomento affinché lo script funzioni. Ovvio, ma vale la pena notare per completezza.
msanford,

16
È possibile, sebbene raramente utile, che il primo argomento sia inizializzato ma vuoto; programname "" secondarg third. Il $#controllo controlla in modo inequivocabile il numero di argomenti.
triplo

39
Per un noob, in particolare qualcuno che proviene da un background non di scripting, è anche importante menzionare alcune peculiarità di queste cose. Avresti potuto anche menzionare che abbiamo bisogno di uno spazio dopo l'apertura e la parentesi graffa di chiusura. Altrimenti le cose non funzionano. Sono anch'io un copione (vengo dallo sfondo C) e l'ho trovato difficile. È stato solo quando ho deciso di copiare l'intera cosa "così com'è" che le cose hanno funzionato per me. Fu allora che mi resi conto che dovevo lasciare uno spazio dopo il tutore di apertura e prima di quello di chiusura.
HighOnMeat

72
e per argomenti facoltativiif [ ! -z "$1" ]; then ...
gcb,

347

È meglio dimostrare in questo modo

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

Normalmente devi uscire se hai troppi argomenti.


72
No non lo è: questo ha quello exit 1che di solito vuoi e usa il [[ ]]test che (iirc) è di solito più ragionevole. Quindi, per le persone che copiano ciecamente il codice incollato questa è la risposta migliore.
pastore,

42
Per saperne di più sulla differenza tra [] e [[]] vedi stackoverflow.com/questions/3427872/…
Sebastián Grignoli,

104

In alcuni casi è necessario verificare se l'utente ha passato un argomento allo script e, in caso contrario, tornare a un valore predefinito. Come nello script seguente:

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

Qui se l'utente non ha passato scaleil secondo parametro, avvio l'emulatore Android -scale 1per impostazione predefinita. ${varname:-word}è un operatore di espansione. Esistono anche altri operatori di espansione:

  • ${varname:=word}che imposta il non definito varnameinvece di restituire il wordvalore;
  • ${varname:?message}che restituisce varnamese è definito e non è nullo o stampa messagee interrompe lo script (come nel primo esempio);
  • ${varname:+word}che restituisce wordsolo se varnameè definito e non è nullo; restituisce null altrimenti.

1
L'esempio sopra sembra usare ${varname?message}. L'extra è :un refuso o cambia comportamento?
Eki

6
Ehi, ":" è un comando incorporato e una scorciatoia per / bin / true in questo esempio. Rappresenta un comando do-nothing che sostanzialmente ignora gli argomenti forniti. È essenziale in questo test per impedire all'interprete di provare a eseguire il contenuto di "$ varname" (che sicuramente NON si desidera che accada). Vale anche la pena notare; puoi testare tutte le variabili con questo metodo che desideri. E tutto con messaggi di errore specifici. vale a dire: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
user.friendly

48

Provare:

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

4
Perché hai bisogno di virgolette doppie per $#e 0?
user13107

1
Nessun problema se usiamo senza virgolette come $ # e 0
Ranjithkumar T

su windows, questo è l'unico modo per andare.
Lajos Meszaros,

2
Questa risposta fornisce un ottimo punto di partenza per una sceneggiatura che ho appena creato. Grazie per aver mostrato elseanche questo.
Chris K,

2
@ user13107 le variabili tra virgolette doppie in bash impediscono il globbing (ovvero l'espansione di nomi di file simili foo*) e la suddivisione delle parole (ovvero la divisione del contenuto se il valore contiene spazi bianchi). In questo caso non è necessario citare $#perché entrambi questi casi non si applicano. Anche la citazione di 0non è necessaria, ma alcune persone preferiscono citare i valori poiché sono veramente stringhe e questo lo rende più esplicito.
Dennis,

39

Un altro modo per rilevare se gli argomenti sono stati passati allo script:

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

Si noti che (( expr ))causa l'espressione da valutare secondo le regole dell'aritmetica della shell .

Per uscire in assenza di argomenti, si può dire:

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

Un altro modo (analogo) per dire quanto sopra sarebbe:

let $# || echo No arguments supplied

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

help let dice:

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 questo potrebbe essere il metodo peggiore se si convalida l'esistenza di un argomento. Inoltre può innescare la sostituzione della storia e potenzialmente fare cose cattive.
user.friendly

2
invece del exitquale uccide il mio processo zsh, io uso quello returnche non lo uccide
Timo

Perché dovrebbe ((!$#))innescare la sostituzione della storia?
Zhro,

25

Uso spesso questo frammento per semplici script:

#!/bin/bash

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

1
Quindi, questo deve essere usato in te hai bisogno solo di un argomento?
Danijel,

21

Solo perché c'è un altro punto base da sottolineare aggiungo che puoi semplicemente testare la tua stringa è nulla:

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

Allo stesso modo, se ti aspetti un conteggio degli arg, prova il tuo ultimo:

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

e così via con qualsiasi arg o var


4

Se desideri verificare se esiste l'argomento, puoi verificare se il numero di argomenti è maggiore o uguale al numero dell'argomento di destinazione.

Il seguente script dimostra come funziona

test.sh

#!/usr/bin/env bash

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

produce il seguente output

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

Come un piccolo promemoria, gli operatori di verifica numerici in Bash funzionano solo su numeri interi ( -eq, -lt, -ge, etc.)

Mi piace assicurarmi che i miei $ var siano ints di

var=$(( var + 0 ))

prima di testarli, giusto per difendermi dall'errore "[: integer arg required".


1
Trucco pulito, ma per favore nota: a causa dell'incapacità di bash di gestire i float in aritmetica, questo metodo può causare un errore di sintassi e restituire un valore diverso da zero che sarebbe un ostacolo in cui è abilitato errexit. var=$(printf "%.0f" "$var")può gestire i float ma soffre dell'uscita diversa da zero quando viene data una stringa. Se non ti dispiace un awk, questo uso metodo che sembra essere il più robusto di far rispettare un numero intero: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Se var non è impostato, il valore predefinito è "0". Se var è un float, viene arrotondato al numero intero più vicino. Anche i valori negativi possono essere utilizzati.
user.friendly

0

una convalida della funzione bash di linea

myFunction() {

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

}

aggiungi il nome e l'utilizzo della funzione

myFunction() {

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

}

aggiungi la validazione per verificare se intero

per aggiungere ulteriore convalida, ad esempio per verificare se l'argomento passato è un numero intero, modificare la convalida di una riga per chiamare una funzione di convalida:

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

quindi, costruisci una funzione di validazione che convalida l'argomento, restituendo 0 in caso di successo, 1 in caso di fallimento e una funzione die che interrompe lo script in caso di fallimento

validateIntegers() {

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

}

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

Ancora più semplice: basta usare set -u

set -u si assicura che ogni variabile referenziata sia impostata quando viene usata, quindi basta impostarla e dimenticarla

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.