Wie ermittle ich, ob eine Bash-Variable leer ist?

Antworten:

1053

Dies gibt true zurück, wenn eine Variable nicht gesetzt oder auf die leere Zeichenfolge ("") gesetzt ist.

if [ -z "$VAR" ];
duffbeer703
quelle
14
Umfasst dies, wenn eine Variable auf den Wert "" gesetzt ist?
Brent,
11
Ja, es werden ... "-z" Tests für eine Zeichenfolge mit der Länge Null durchgeführt.
David Z
91
if [ ! -z "$VAR" ];
Aaron Copley
263
das Gegenteil von -zist-n if [ -n "$VAR" ];
Felipe Alvarez
19
Die doppelten Anführungszeichen stellen sicher, dass die Variable nicht aufgeteilt wird. Ein einfaches $varElement in einer Befehlszeile wird durch sein Leerzeichen in eine Liste von Parametern aufgeteilt, wobei "$var"es sich immer nur um einen Parameter handelt. Das Zitieren von Variablen ist häufig eine gute Praxis und verhindert, dass Sie auf Dateinamen stoßen, die (unter anderem) Leerzeichen enthalten. Beispiel: a="x --help"Versuchen cat $aSie es anschließend mit der Hilfeseite für cat. Dann versuchen cat "$a"Sie es - es wird (normalerweise) sagen cat: x --help: No such file or directory. Kurz gesagt, zitiere früh und zitiere oft und du wirst es so gut wie nie bereuen.
Score_Under
247

Wenn Sie sich in Bash nicht mit der Portierbarkeit auf Shells befassen, die diese nicht unterstützen, sollten Sie immer die doppelte Klammer verwenden:

Eines der folgenden:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

In Bash sind die Anführungszeichen in doppelten eckigen Klammern nicht erforderlich. Sie können den Test für eine Variable vereinfachen , die tut einen Wert enthalten:

if [[ $variable ]]

Diese Syntax ist mit ksh kompatibel (zumindest ksh93). Es funktioniert nicht in reinen POSIX- oder älteren Bourne-Shells wie sh oder dash.

Weitere Informationen zu den Unterschieden zwischen doppelten und einfachen eckigen Klammern finden Sie in meiner Antwort hier und in BashFAQ / 031 .

Sie können testen, ob eine Variable speziell nicht gesetzt ist (im Gegensatz zu einer leeren Zeichenfolge):

if [[ -z ${variable+x} ]]

wobei das "x" beliebig ist.

Wenn Sie wissen möchten, ob eine Variable null ist, aber nicht nicht gesetzt wurde:

if [[ -z $variable && ${variable+x} ]]
Dennis Williamson
quelle
1
Das if [[ $variable ]]hat für mich gut funktioniert und brauchte nicht einmal das set -u, was für eine der anderen vorgeschlagenen Lösungen erforderlich war.
Teemu Leisti
3
Ich denke, das ist besser als die akzeptierte Antwort.
qed
2
Warum empfehlen Sie eine nicht tragbare Funktion, wenn dies keinen Nutzen bringt?
Alastair Irvine
19
@AlastairIrvine: Ich erwähne die Portabilität im ersten Satz meiner Antwort, der Fragentitel und der Text enthalten das Wort "Bash" und die Frage ist mit bash markiert , und die doppelte Klammerstruktur bietet in vielerlei Hinsicht klare Vorteile . Und ich empfehle aus Gründen der Konsistenz und Wartbarkeit nicht, Bracket-Stile zu mischen. Wenn Sie maximale Portabilität mit dem niedrigsten gemeinsamen Nenner benötigen, verwenden Sie shanstelle von Bash. Wenn Sie die erweiterten Funktionen benötigen, verwenden Sie Bash und nutzen Sie es vollständig.
Dennis Williamson
2
@BrunoBronosky: Ich habe die Bearbeitung rückgängig gemacht. Es gibt keine Anforderung für ;am Ende. Die thenkann in der nächsten Zeile ohne Semikolon stehen.
Dennis Williamson
230

Eine Variable in bash (und jede POSIX-kompatible Shell) kann sich in einem von drei Zuständen befinden:

  • nicht gesetzt
  • auf die leere Zeichenkette setzen
  • Auf eine nicht leere Zeichenfolge setzen

Die meiste Zeit müssen Sie nur wissen, ob eine Variable auf eine nicht leere Zeichenfolge festgelegt ist, aber gelegentlich ist es wichtig, zwischen nicht festgelegt und auf die leere Zeichenfolge festgelegt zu unterscheiden.

Die folgenden Beispiele zeigen, wie Sie die verschiedenen Möglichkeiten testen können und ob dies in bash oder einer POSIX-kompatiblen Shell funktioniert:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

Hier ist das Gleiche, aber in handlicher Tabellenform:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

Das ${VAR+foo}Konstrukt wird zu der leeren Zeichenfolge erweitert, wenn VARes nicht festgelegt ist, oder zu, foowenn VARes auf etwas festgelegt ist (einschließlich der leeren Zeichenfolge).

Das ${VAR-foo}Konstrukt wird auf den Wert von VARif set (einschließlich set für die leere Zeichenfolge) und fooif unset erweitert. Dies ist nützlich, um vom Benutzer überschreibbare Standardeinstellungen bereitzustellen (z. B. ${COLOR-red}zu verwenden, es redsei denn, die Variable COLORwurde auf etwas festgelegt).

Der Grund, warum [ x"${VAR}" = x ]oft empfohlen wird, um zu testen, ob eine Variable entweder nicht gesetzt oder auf die leere Zeichenfolge gesetzt ist, liegt darin, dass einige Implementierungen des [Befehls (auch bekannt als test) fehlerhaft sind. Wenn VARauf so etwas wie gesetzt ist -n, werden einige Implementierungen bei der Angabe das Falsche tun, [ "${VAR}" = "" ]da das erste Argument zu [fälschlicherweise als -nOperator interpretiert wird , nicht als Zeichenfolge.

Richard Hansen
quelle
3
Das Testen für eine Variable, die auf die leere Zeichenfolge festgelegt ist, kann auch mit ausgeführt werden [ -z "${VAR-set}" ].
Nwellnhof
@nwellnhof: Danke! Ich habe meine Antwort aktualisiert, um die kürzere Syntax zu verwenden.
Richard Hansen
Was ist der Unterschied zwischen dem ersten und dem letzten Konstrukt? Beide entsprechen "VAR ist entweder nicht gesetzt oder auf eine nicht leere Zeichenfolge gesetzt".
Faheem Mitha
1
@FaheemMitha: Es ist nicht deine Schuld - meine Antwort war schwer zu lesen. Ich habe eine Tabelle hinzugefügt, um die Antwort hoffentlich klarer zu machen.
Richard Hansen
2
Die nicht gesetzten Prüfungen sind nicht zuverlässig. Wenn der Benutzer set -uoder set -o nounsetin bash anruft, führt der Test nur zum Fehler "bash: VAR: ungebundene Variable". Unter stackoverflow.com/a/13864829 finden Sie eine zuverlässigere Überprüfung auf nicht gesetzte Werte . Ich überprüfe, ob eine Variable null ist oder nicht [ -z "${VAR:-}" ]. Meine Prüfung, ob eine Variable nicht leer ist, ist [ "${VAR:-}" ].
Kevin Jin
38

-z ist der beste Weg.

Eine andere Option, die ich verwendet habe, ist das Setzen einer Variablen, die jedoch von einer anderen Variablen außer Kraft gesetzt werden kann, z

export PORT=${MY_PORT:-5432}

Wenn die $MY_PORTVariable leer ist, PORTwird sie auf 5432 gesetzt, andernfalls wird PORT auf den Wert von gesetzt MY_PORT. Beachten Sie, dass die Syntax den Doppelpunkt und den Bindestrich enthält.

Rory
quelle
Habe das heute versehentlich gefunden und es war genau das, was ich wollte. Vielen Dank! Ich muss set -o nounsetin einigen Skripten tolerieren .
Opello
24

Wenn Sie zwischen den Fällen "set-empty" und "unset" unterscheiden möchten, prüfen Sie die Option -u für bash:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true
MikeyB
quelle
8

Eine Alternative, die ich gesehen habe, [ -z "$foo" ]ist die folgende, aber ich bin nicht sicher, warum die Leute diese Methode anwenden, weiß jemand?

[ "x${foo}" = "x" ]

Wenn Sie nicht gesetzte Variablen (entweder von set -uoder set -o nounset) nicht zulassen, treten bei beiden Methoden Probleme auf. Hierfür gibt es eine einfache Lösung:

[ -z "${foo:-}" ]

Hinweis: Dadurch bleibt Ihre Variable undef.

errant.info
quelle
3
Es gibt einen Kommentar zur Alternative zu -zunter pubs.opengroup.org/onlinepubs/009695399/utilities/test.html . Grundsätzlich ist es keine Alternative zu -z. Vielmehr werden Fälle behandelt, in denen $fooeine Erweiterung auf einen Meta-Buchstaben möglich ist, der verwirrt ist [oder von testdiesem verwirrt wird. Wenn Sie am Anfang ein beliebiges Nicht-Metazeichen setzen, wird diese Möglichkeit ausgeschlossen.
James Sneeringer
6

Die Frage lautet , wie zu überprüfen ist, ob eine Variable eine leere Zeichenfolge ist, und die besten Antworten dafür sind bereits gegeben.
Aber ich bin hier gelandet, nachdem eine Zeit lang die Programmierung in PHP abgelaufen war, und was ich tatsächlich suchte, war eine Überprüfung wie die leere Funktion in PHP, die in einer Bash-Shell arbeitet.
Nachdem ich die Antworten gelesen hatte, stellte ich fest, dass ich in Bash nicht richtig dachte, aber in diesem Moment wäre eine Funktion wie leer in PHP in meinem Bash-Code soooo praktisch gewesen.
Wie ich glaube , dies anderen passieren kann, habe ich beschlossen , die PHP - leer - Funktion in bash zu konvertieren

Nach dem PHP - Handbuch :
Eine Variable wird als leer betrachtet, wenn sie nicht existiert oder wenn ihr Wert einer der folgenden Werte ist:

  • "" (eine leere Zeichenfolge)
  • 0 (0 als Ganzzahl)
  • 0,0 (0 als Float)
  • "0" (0 als Zeichenfolge)
  • ein leeres Array
  • Eine deklarierte Variable, aber ohne Wert

Natürlich können die Groß- und Kleinschreibung nicht in Bash konvertiert werden, daher werden sie weggelassen.

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



Anwendungsbeispiel:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



Demo:
das folgende Snippet:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

Ausgänge:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

In einer Bash-Logik können die Prüfungen auf Null in dieser Funktion imho Nebenprobleme verursachen. Jeder, der diese Funktion verwendet, sollte dieses Risiko bewerten und möglicherweise beschließen, diese Prüfungen abzuschneiden und nur die erste zu belassen.

Luca Borrione
quelle
Innerhalb der Funktion empty- warum hast du geschrieben [[ $( echo "1" ) ]] ; returnanstatt einfach return 1?
Dor
5

Das gesamte Wenn-Dann und -Z sind nicht erforderlich.

["$ foo"] && echo "foo ist nicht leer"
["$ foo"] || echo "foo ist ja leer"

quelle
3
Das wird scheitern, wenn foo nur Leerzeichen enthält
Brian
2
Scheitert auch in einigen Shells, wenn foo mit einem Bindestrich beginnt, da dies als Option interpretiert wird. ZB auf Solaris sind ksh , zsh und bash kein Problem, sh und / bin / test
schlagen
4

Dies gilt genau dann, wenn $ FOO gesetzt und leer ist:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

quelle
4

Persönlich bevorzugen klarere Weise zu überprüfen:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi
Fedir RYKHTIK
quelle
1
Einige Shells akzeptieren kein doppeltes Gleichheitszeichen.
Dennis Williamson
1
Die Frage war über Bash. Ich benutze Bash. Funktioniert gut für mich. Über was genau sprichst du?
Fedir RYKHTIK
2
Wenn Sie Bash verwenden, sollten Sie doppelte eckige Klammern verwenden. Mein vorheriger Kommentar war eine einfache Feststellung für diejenigen, die möglicherweise Ihre Antwort lesen und eine andere Shell verwenden.
Dennis Williamson
einfache eckige Klammern sind in diesem Fall in Ordnung
Luca Borrione
4

Oneliner-Erweiterung der Lösung von duffbeer703 :

#! /bin/bash
[ -z "$1" ] || some_command_that_needs_$1_parameter
andrej
quelle
4

Meine 5 Cent: Es gibt auch eine kürzere Syntax als if ...diese:

VALUE="${1?"Usage: $0 value"}"

Diese Zeile setzt VALUE, wenn ein Argument angegeben wurde, und gibt im Fehlerfall eine Fehlermeldung mit der Nummer der Skriptzeile aus (und beendet die Skriptausführung).

Ein weiteres Beispiel finden Sie im Abs -Guide (Suche nach «Beispiel 10-7»).

gluk47
quelle
0

Keine exakte Antwort, aber auf diesen Trick gestoßen. Wenn die Zeichenfolge, nach der Sie suchen, von "einem Befehl" stammt, können Sie den Befehl tatsächlich in einer Umgebung speichern. Variable und führen Sie es dann jedes Mal für die if-Anweisung aus, dann sind keine Klammern erforderlich!

Zum Beispiel dieser Befehl, der bestimmt, ob Sie unter Debian sind:

grep debian /proc/version

vollständiges Beispiel:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

Dies ist also wie eine indirekte Methode (es wird jedes Mal neu ausgeführt), um nach einer leeren Zeichenfolge zu suchen (es wird zufällig nach einer Fehlerantwort vom Befehl gesucht, es wird jedoch auch eine leere Zeichenfolge zurückgegeben).

Rogerdpack
quelle