Vraag Hoe te bepalen of een bash-variabele leeg is?


Wat is de beste manier om te bepalen of een variabele in bash leeg is ("")?

Ik heb gehoord dat het wordt aanbevolen dat ik het doe if [ "x$variable" = "x" ]

Is dat de correct manier? (er moet iets meer rechtlijnig zijn)


719
2018-05-12 17:54


oorsprong




antwoorden:


Hierdoor wordt true geretourneerd als een variabele niet is ingesteld of is ingesteld op de lege tekenreeks ("").

if [ -z "$VAR" ];

980
2018-05-12 18:06



Omvat dat als een variabele IS INSTELLEN naar een waarde van ""? - Brent
Ja, het doet ... "-z" test voor een string van nul lengte. - David Z
if [ ! -z "$VAR" ]; - Aaron Copley
de inverse van -z is -n  if [ -n "$VAR" ]; - Felipe Alvarez
De dubbele aanhalingstekens zorgen ervoor dat de variabele niet wordt gesplitst. Een eenvoudige $var op een opdrachtregel zal worden opgedeeld door zijn witruimte in een lijst met parameters, terwijl "$var" zal altijd maar één parameter zijn. Het citeren van variabelen is vaak een goede gewoonte en voorkomt dat je onder de bestandsnamen met witruimte (onder andere) struikelt. Voorbeeld: na het doen a="x --help", proberen cat $a - het zal je de helppagina geven voor cat. Probeer het dan cat "$a" - het zal (meestal) zeggen cat: x --help: No such file or directory. Kortom: citeer vroeg en citeer vaak en je zult er bijna nooit spijt van hebben. - Score_Under


Als je in Bash niet bezig bent met draagbaarheid voor shells die dit niet ondersteunen, moet je altijd de syntaxis van de dubbele bracket gebruiken:

Een van de volgende:

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

In Bash, met behulp van dubbele vierkante haken, zijn de aanhalingstekens niet nodig. Je kunt de test voor een variabele dat vereenvoudigen doet een waarde bevatten voor:

if [[ $variable ]]

Deze syntaxis is compatibel met ksh (hoe dan ook, in elk geval ksh93). Het werkt niet in pure POSIX of oudere Bourne-shells zoals sh of dash.

Zien mijn antwoord hier en BashFAQ / 031 voor meer informatie over de verschillen tussen dubbele en enkele vierkante haken.

U kunt testen om te zien of een variabele specifiek niet is ingesteld (anders dan een lege reeks):

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

waar de "x" willekeurig is.

Als u wilt weten of een variabele null maar niet unset is:

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

227
2018-02-25 03:37



Dat if [[ $variable ]] werkte goed voor mij, en had zelfs de set -u dat werd vereist door een van de andere voorgestelde oplossingen. - Teemu Leisti
Ik denk dat dit beter is dan het geaccepteerde antwoord. - qed
Waarom beveel je een niet-draagbare functie aan als dat geen voordeel oplevert? - Alastair Irvine
@AlastairIrvine: ik vermeld draagbaarheid in de eerste zin van mijn antwoord, de titel van de vraag en het lichaam bevatten het woord "Bash" en de vraag is getagd bashen de dubbele beugelstructuur biedt duidelijke voordelen op veel manieren. En ik raad het niet aan om beugelstijlen te mixen om redenen van consistentie en onderhoudbaarheid. Als u een maximale, laagste gemene overdraagbaarheid van de noemer nodig heeft, gebruik deze dan sh in plaats van Bash. Als je de verhoogde mogelijkheden die het biedt nodig hebt, gebruik je Bash en gebruik je het volledig. - Dennis Williamson
@BrunoBronosky: ik heb de bewerking teruggezet. Er is geen vereiste voor ; aan het einde. De then kan op de volgende regel staan ​​zonder een puntkomma. - Dennis Williamson


Een variabele in bash (en elke POSIX-compatibele shell) kan zich in een van de volgende drie toestanden bevinden:

  • ongezet
  • stel in op de lege string
  • stel in op een niet-lege string

Meestal moet u alleen weten of een variabele is ingesteld op een niet-lege tekenreeks, maar af en toe is het belangrijk om onderscheid te maken tussen Uitschakelen en instellen op de lege tekenreeks.

Hieronder volgen voorbeelden van hoe je de verschillende mogelijkheden kunt testen, en het werkt in bash of elke POSIX-compatibele shell:

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 is hetzelfde, maar in handige tabelvorm:

                        +-------+-------+-----------+
                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      |
+-----------------------+-------+-------+-----------+

De ${VAR+foo} construct breidt uit naar de lege reeks als VAR is uitgeschakeld of naar foo als VAR is ingesteld op alles (inclusief de lege tekenreeks).

De ${VAR-foo} construct breidt uit naar de waarde van VAR indien ingesteld (inclusief ingesteld op de lege reeks) en foo indien uitgeschakeld. Dit is handig voor het bieden van door de gebruiker te overschrijven standaardwaarden (bijv. ${COLOR-red} zegt te gebruiken red tenzij de variabele COLOR is ergens op ingesteld).

De reden waarom [ x"${VAR}" = x ] wordt vaak aanbevolen om te testen of een variabele niet is ingesteld of is ingesteld op de lege tekenreeks, omdat sommige implementaties van de [ commando (ook bekend als test) zijn buggy. Als VAR is ingesteld op iets als -n, dan zullen sommige implementaties het verkeerde doen wanneer ze worden gegeven [ "${VAR}" = "" ] omdat het eerste argument aan [ wordt ten onrechte geïnterpreteerd als de -n operator, geen string.


205
2018-04-24 20:39



Testen voor een variabele ingesteld op de lege reeks kan ook worden gedaan met [ -z "${VAR-set}" ]. - nwellnhof
@nwellnhof: Bedankt! Ik heb mijn antwoord bijgewerkt om de kortere syntaxis te gebruiken. - Richard Hansen
@FaheemMitha: Het is niet jouw schuld - mijn antwoord was moeilijk te lezen. Ik heb een tabel toegevoegd om het antwoord hopelijk duidelijker te maken. - Richard Hansen
@RichardHansen: Bedankt, dat is een nuttige toevoeging. - Faheem Mitha
De niet-ingestelde controles zijn niet betrouwbaar. Als de gebruiker heeft gebeld set -u of set -o nounset in bash, dan zal de test gewoon resulteren in de fout "bash: VAR: niet-afhankelijke variabele". Zien stackoverflow.com/a/13864829 voor een meer betrouwbare uitschakelcontrole. Mijn go-to controleren of een variabele null of unset is [ -z "${VAR:-}" ]. Mijn controle of een variabele niet leeg is, is [ "${VAR:-}" ]. - Kevin Jin


-z is de beste manier.

Een andere optie die ik heb gebruikt, is om een ​​variabele in te stellen, maar deze kan worden opgeheven door een andere variabele, bijvoorbeeld

export PORT=${MY_PORT:-5432}

Als het $MY_PORT variabele is leeg PORT wordt ingesteld op 5432, anders wordt PORT ingesteld op de waarde van MY_PORT. Let op de syntaxis inclusief de dubbele punt en het streepje.


36
2018-06-11 13:19



Per ongeluk vond dit vandaag, en het was precies wat ik wilde. Bedankt! Ik moet het verdragen set -o nounset in sommige scripts. - opello


Als je geïnteresseerd bent in het onderscheiden van de gevallen van set-leeg versus unset status, kijk dan naar de -u optie voor 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

24
2018-05-12 18:21





Een alternatieve die ik gezien heb [ -z "$foo" ] is het volgende, maar ik weet niet zeker waarom mensen deze methode gebruiken, weet iemand het?

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

Hoe dan ook, als u niet-instelbare variabelen weigert (ofwel door set -u of set -o nounset), dan kom je problemen tegen met beide methoden. Er is een eenvoudige oplossing voor dit:

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

Opmerking: hierdoor blijft je variabele undef achter.


8
2017-10-20 03:58



Er is een opmerking over het alternatief voor -z op pubs.opengroup.org/onlinepubs/009695399/utilities/test.html. Kortom, het is niet bedoeld als een alternatief voor -z. Integendeel, het behandelt zaken waar $foo zou kunnen uitbreiden naar iets dat begint met een metateken dat [ of test zou worden verward door. Door een willekeurig niet-metachaar aan het begin te plaatsen, wordt die mogelijkheid geëlimineerd. - James Sneeringer


De vraag vraagt hoe te controleren of een variabele een lege string is en daarvoor zijn de beste antwoorden al gegeven.
Maar ik kwam hier terecht nadat een periode voorbij was gegaan met programmeren in php en wat ik eigenlijk zocht was een vinkje als het lege functie in php werken in een bash-shell.
Na het lezen van de antwoorden besefte ik dat ik niet goed zat te denken in bash, maar hoe dan ook op dat moment een functie als leeg in php zou zoooo handig zijn geweest in mijn bash-code.
Omdat ik denk dat dit met anderen kan gebeuren, heb ik besloten de php-lege functie in bash te converteren

Volgens de php handleiding:
een variabele wordt als leeg beschouwd als deze niet bestaat of als de waarde ervan een van de volgende is:

  • "" (een lege string)
  • 0 (0 als een geheel getal)
  • 0.0 (0 als een float)
  • "0" (0 als een string)
  • een lege array
  • een variabele gedeclareerd, maar zonder een waarde

Natuurlijk nul en vals cases kunnen niet worden omgezet in bash, dus worden ze weggelaten.

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 "" ) ]]
}



Voorbeeld van gebruik:

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



demo:
het volgende fragment:

#!/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

uitgangen:

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

Dat gezegd hebbende, in een bash-logica kunnen de controles op nul in deze functie nevenproblemen veroorzaken. Imho, iedereen die deze functie gebruikt, moet dit risico evalueren en misschien besluiten om die controles af te snijden en alleen de eerste te laten.


6
2017-08-31 20:11



Binnen de functie empty - waarom heb je geschreven? [[ $( echo "1" ) ]] ; return in plaats van simpelweg return 1 ? - Dor


de gehele if-then en -z zijn onnodig.

["$ foo"] && echo "foo is niet leeg"
["$ foo"] || echo "foo is inderdaad leeg"

5
2018-01-26 14:02



Dat zal mislukken als foo alleen spaties bevat - Brian
Zal ook in sommige shells falen als foo begint met een streepje, omdat het als een optie wordt geïnterpreteerd. Bijv. op solaris ksh, zsh en bash zijn geen probleem, sh en / Bin / test zal mislukken - ktf


Dit klopt precies wanneer $ FOO is ingesteld en leeg is:

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

4
2018-05-20 20:52





Persoonlijk liever een duidelijkere manier om te controleren:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi

4
2017-12-09 15:15



Sommige shells accepteren het dubbele gelijkteken niet. - Dennis Williamson
De vraag ging over bash. Ik gebruik bash. Werkt goed voor mij. Waar praat je precies over? - Fedir RYKHTIK
Als u Bash gebruikt, moet u dubbele vierkante haakjes gebruiken. Mijn vorige opmerking was een simpele verklaring van feit voor diegenen die mogelijk jouw antwoord lezen en een andere shell gebruiken. - Dennis Williamson
enkele vierkante haakjes zijn in dit geval ok, zie serverfault.com/questions/52034/... - Luca Borrione