Überprüfen Sie das Vorhandensein eines Eingabearguments in einem Bash-Shell-Skript

1338

Ich muss die Existenz eines Eingabearguments überprüfen. Ich habe das folgende Skript

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

Ich bekomme

[: : integer expression expected

Wie überprüfe ich zuerst das Eingabeargument1, um festzustellen, ob es vorhanden ist?

user775187
quelle

Antworten:

2329

Es ist:

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

Die $#Variable gibt die Anzahl der Eingabeargumente an, an die das Skript übergeben wurde.

Oder Sie können überprüfen, ob ein Argument eine leere Zeichenfolge ist oder nicht:

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

Der -zSwitch testet, ob die Erweiterung von "$ 1" eine Nullzeichenfolge ist oder nicht. Wenn es sich um eine Nullzeichenfolge handelt, wird der Body ausgeführt.

Phoxis
quelle
62
Ich mache es gerne so, in knapper Syntax und trotzdem POSIX akzeptabel. [ -z "$1" ] && echo "No argument supplied" Ich bevorzuge Einzeiler, da sie für mich einfacher sind. und es ist auch schneller Check Exit - Wert, im Vergleich zur Verwendungif
JM Becker
168
Sie möchten wahrscheinlich ein exit 1am Ende Ihrer Echos im if-Block einfügen, wenn das Argument erforderlich ist, damit das Skript funktioniert. Offensichtlich, aber der Vollständigkeit halber erwähnenswert.
Msanford
16
Es ist möglich, obwohl selten nützlich, dass das erste Argument initialisiert, aber leer ist. programname "" secondarg third. Die $#Prüfung prüft eindeutig die Anzahl der Argumente.
Tripleee
39
Für einen Neuling, insbesondere für jemanden, der nicht aus Skripten stammt, ist es auch wichtig, einige Besonderheiten dieser Dinge zu erwähnen. Sie hätten auch erwähnen können, dass wir nach dem Öffnen und Schließen eine Klammer benötigen. Sonst funktionieren die Dinge nicht. Ich bin selbst ein Scripting-Neuling (ich komme aus dem C-Hintergrund) und fand es auf die harte Tour. Erst als ich mich entschied, das Ganze "wie es ist" zu kopieren, funktionierten die Dinge für mich. Dann wurde mir klar, dass ich nach der öffnenden Klammer und vor der schließenden Klammer ein Leerzeichen lassen musste.
HighOnMeat
72
und für optionale if [ ! -z "$1" ]; then ...
Argumente
346

Es ist besser, diesen Weg zu demonstrieren

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

Normalerweise müssen Sie beenden, wenn Sie zu wenige Argumente haben.

Val
quelle
72
Nein, ist es nicht: Dies hat, exit 1was Sie normalerweise wollen, und verwendet den [[ ]]Test, der (iirc) normalerweise vernünftiger ist. Für Leute, die blind Code einfügen, ist dies die bessere Antwort.
Dshepherd
42
Um mehr über den Unterschied zwischen [] und [[]] zu erfahren,
Sebastián Grignoli
104

In einigen Fällen müssen Sie überprüfen, ob der Benutzer ein Argument an das Skript übergeben hat, und wenn nicht, auf einen Standardwert zurückgreifen. Wie im folgenden Skript:

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

Hier, wenn der Benutzer nicht scaleals 2. Parameter übergeben hat, starte ich -scale 1standardmäßig den Android-Emulator mit . ${varname:-word}ist ein Expansionsoperator. Es gibt auch andere Expansionsbetreiber:

  • ${varname:=word}das setzt das undefinierte, varnameanstatt den wordWert zurückzugeben;
  • ${varname:?message}die entweder zurückgibt, varnamewenn sie definiert ist und nicht null ist, oder messagedas Skript druckt und abbricht (wie im ersten Beispiel);
  • ${varname:+word}die wordnur zurückgibt , wenn varnamedefiniert und nicht null ist; Gibt sonst null zurück.
Aleks N.
quelle
1
Das obige Beispiel scheint zu verwenden ${varname?message}. Ist das Extra :ein Tippfehler oder ändert es das Verhalten?
Eki
6
Eki, das ":" ist ein eingebauter Befehl und eine Abkürzung für / bin / true in diesem Beispiel. Es stellt einen Nichtstun-Befehl dar, der die bereitgestellten Argumente grundsätzlich ignoriert. In diesem Test ist es wichtig, dass der Interpreter nicht versucht, den Inhalt von "$ varname" auszuführen (was Sie sicherlich NICHT wollen). Auch erwähnenswert; Mit dieser Methode können Sie beliebig viele Variablen testen. Und das alles mit spezifischen Fehlermeldungen. dh: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
benutzerfreundlich
48

Versuchen:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi
Ranjithkumar T.
quelle
4
Warum brauchen Sie doppelte Anführungszeichen für $#und 0?
user13107
1
Kein Problem, wenn wir ohne doppelte Anführungszeichen wie $ # und 0
Ranjithkumar T
Unter Windows ist dies der einzige Weg.
Lajos Meszaros
2
Diese Antwort bietet einen guten Ausgangspunkt für ein Skript, das ich gerade erstellt habe. Danke, dass du das elseauch gezeigt hast.
Chris K
2
@ user13107 Variablen in doppelten Anführungszeichen in bash verhindern das Globbing (dh das Erweitern von Dateinamen wie foo*) und das Aufteilen von Wörtern (dh das Aufteilen des Inhalts, wenn der Wert Leerzeichen enthält). In diesem Fall ist kein Zitat erforderlich, $#da beide Fälle nicht zutreffen. Das Zitieren von 0ist ebenfalls nicht erforderlich, aber einige Leute bevorzugen das Zitieren von Werten, da es sich wirklich um Zeichenfolgen handelt, und das macht es expliziter.
Dennis
39

Eine andere Möglichkeit, um festzustellen, ob Argumente an das Skript übergeben wurden:

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

Beachten Sie, (( expr ))dass der Ausdruck gemäß den Regeln der Shell-Arithmetik ausgewertet wird .

Um ohne Argumente zu beenden, kann man sagen:

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

Eine andere (analoge) Art, das Obige zu sagen, wäre:

let $# || echo No arguments supplied

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

help let sagt:

let: let arg [arg ...]

  Evaluate arithmetic expressions.

  ...

  Exit Status:
  If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
devnull
quelle
2
-1 Dies ist möglicherweise die schlechteste Methode, wenn das Vorhandensein eines Arguments überprüft wird. Außerdem kann dies die Ersetzung des Verlaufs auslösen und möglicherweise schlechte Dinge bewirken.
Benutzerfreundlich
2
Anstatt exitmeinen zsh-Prozess zu beenden, verwende ich einen, returnder ihn nicht beendet
Timo,
Warum sollte ((!$#))eine Historienersetzung ausgelöst werden?
Zhro
25

Ich benutze dieses Snippet oft für einfache Skripte:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi
f2cx
quelle
1
Also, dies soll verwendet werden, wenn Sie nur ein Argument benötigen?
Danijel
21

Nur weil es einen weiteren Basispunkt gibt, möchte ich hinzufügen, dass Sie einfach testen können, ob Ihre Zeichenfolge null ist:

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

Wenn Sie eine Arg-Anzahl erwarten, testen Sie einfach Ihre letzte:

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

und so weiter mit jedem arg oder var

seorphiert
quelle
4

Wenn Sie überprüfen möchten, ob das Argument vorhanden ist, können Sie überprüfen, ob die Anzahl der Argumente größer oder gleich Ihrer Zielargumentnummer ist.

Das folgende Skript zeigt, wie dies funktioniert

test.sh

#!/usr/bin/env bash

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

erzeugt die folgende Ausgabe

$ ./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
Brad Parks
quelle
3

Als kleine Erinnerung, die numerische Test Operatoren in Bash arbeiten nur auf ganze Zahlen ( -eq, -lt, -ge, etc.)

Ich möchte sicherstellen, dass meine $ vars Ints von sind

var=$(( var + 0 ))

bevor ich sie teste, nur um mich gegen den Fehler "[: integer arg required" zu verteidigen.

Cwissy
quelle
1
Ordentlicher Trick, aber bitte beachten Sie: Aufgrund der Unfähigkeit von bash, Floats in Arithmetik zu verarbeiten, kann diese Methode einen Syntaxfehler verursachen und einen Wert ungleich Null zurückgeben, was ein Hindernis wäre, wenn errexit aktiviert ist. var=$(printf "%.0f" "$var")kann mit Floats umgehen, leidet jedoch unter dem Exit ungleich Null, wenn eine Zeichenfolge angegeben wird. Wenn Ihnen ein awk nichts ausmacht, scheint diese Methode, die ich verwende, die robusteste zu sein, um eine Ganzzahl zu erzwingen : var=$(<<<"$var" awk '{printf "%.0f", $0}'). Wenn var nicht gesetzt ist, wird standardmäßig "0" verwendet. Wenn var ein Float ist, wird es auf die nächste Ganzzahl gerundet. Negative Werte sind ebenfalls in Ordnung.
Benutzerfreundlich
0

Validierung der One-Liner-Bash-Funktion

myFunction() {

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

}

Funktionsnamen und Verwendung hinzufügen

myFunction() {

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

}

Fügen Sie eine Validierung hinzu, um zu überprüfen, ob eine Ganzzahl vorliegt

Um eine zusätzliche Validierung hinzuzufügen, z. B. um zu überprüfen, ob das übergebene Argument eine Ganzzahl ist, ändern Sie die Validierung eines Liners, um eine Validierungsfunktion aufzurufen:

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

Erstellen Sie dann eine Validierungsfunktion, die das Argument validiert und 0 bei Erfolg, 1 bei Fehler und eine Die-Funktion zurückgibt, die das Skript bei Fehler abbricht

validateIntegers() {

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

}

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

Noch einfacher - einfach benutzen set -u

set -u stellt sicher, dass jede referenzierte Variable festgelegt ist, wenn sie verwendet wird. Legen Sie sie einfach fest und vergessen Sie sie

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

}
AndrewD
quelle