Hoe controleer je of een variabele is ingesteld in Bash?

Hoe weet ik of een variabele is ingesteld in Bash?

Hoe controleer ik bijvoorbeeld of de gebruiker de eerste parameter aan een functie heeft gegeven?

function a {
    # if $1 is set ?
}

Antwoord 1, autoriteit 100%

(Meestal) Op de juiste manier

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

waar ${var+x}een parameteruitbreidingdie niets oplevert als varniet is ingesteld, en anders de tekenreeks xvervangt.

Citaten uitweiding

Citaten kunnen worden weggelaten (we kunnen dus ${var+x}zeggen in plaats van "${var+x}") omdat deze syntaxis & gebruik garandeert dat dit alleen uitbreidt naar iets waarvoor geen aanhalingstekens nodig is (omdat het ofwel uitbreidt naar x(die geen woordonderbrekingen bevat, dus geen aanhalingstekens nodig), of naar niets (wat resulteert in [ -z ], wat handig evalueert tot dezelfde waarde (true) die [ -z "" ]ook doet)).

Hoewel aanhalingstekens veilig kunnen worden weggelaten, was het niet meteen voor iedereen duidelijk (het was zelfs niet duidelijk voor de eerste auteur van deze citatenverklaringdie ook een grote Bash-codeerder is), zou het soms beter zijn om de oplossing met aanhalingstekens te schrijven als [ -z "${var+x}" ], tegen de zeer kleine mogelijke kosten van een O(1) snelheidsboete. De eerste auteur heeft dit ook als opmerking toegevoegd naast de code die deze oplossing gebruikt en de URL naar dit antwoord geeft, die nu ook de uitleg bevat waarom de aanhalingstekens veilig kunnen worden weggelaten.

(vaak) op de verkeerde manier

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

Dit is vaak verkeerd omdat er geen onderscheid wordt gemaakt tussen een variabele die niet is ingesteld en een variabele die is ingesteld op de lege tekenreeks. Dat wil zeggen, als var='', dan zal de bovenstaande oplossing “var is blank” uitvoeren.

Het onderscheid tussen uitgeschakeld en “ingesteld op de lege tekenreeks” is essentieel in situaties waarin de gebruiker een extensie of een extra lijst met eigenschappen moet specificeren, en het niet specificeren hiervan standaard een niet-lege waarde is, terwijl het specificeren van de lege tekenreeks zou ervoor moeten zorgen dat het script een lege extensie of lijst met extra eigenschappen gebruikt.

Het onderscheid is misschien niet in elk scenario essentieel. In die gevallen is [ -z "$var" ]prima.


Antwoord 2, autoriteit 39%

Om te controleren op niet-null/niet-nul tekenreeksvariabele, d.w.z. indien ingesteld, gebruik

if [ -n "$1" ]

Het is het tegenovergestelde van -z. Ik merk dat ik -nmeer gebruik dan -z.

Je zou het als volgt gebruiken:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi

Antwoord 3, autoriteit 22%

Zo kunt u testen of een parameter uitgeschakeld, leeg (“Null”)of ingesteld met een waardeis:

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |       parameter      |     parameter   |    parameter    |
|   in script:       |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

Bron: POSIX: parameteruitbreiding:

In alle gevallen die worden weergegeven met “substitute”, wordt de uitdrukking vervangen door de getoonde waarde. In alle gevallen die worden weergegeven met “assign”, wordt aan de parameter die waarde toegewezen, die ook de uitdrukking vervangt.

Om dit in actie te laten zien:

+--------------------+----------------------+-----------------+-----------------+
|   Expression       |  FOO="world"         |     FOO=""      |    unset FOO    |
|   in script:       |  (Set and Not Null)  |  (Set But Null) |     (Unset)     |
+--------------------+----------------------+-----------------+-----------------+
| ${FOO:-hello}      | world                | hello           | hello           |
| ${FOO-hello}       | world                | ""              | hello           |
| ${FOO:=hello}      | world                | FOO=hello       | FOO=hello       |
| ${FOO=hello}       | world                | ""              | FOO=hello       |
| ${FOO:?hello}      | world                | error, exit     | error, exit     |
| ${FOO?hello}       | world                | ""              | error, exit     |
| ${FOO:+hello}      | hello                | ""              | ""              |
| ${FOO+hello}       | hello                | hello           | ""              |
+--------------------+----------------------+-----------------+-----------------+

Antwoord 4, autoriteit 12%

Hoewel de meeste van de hier vermelde technieken correct zijn, ondersteunt bash 4.2een daadwerkelijke test voor de aanwezigheid van een variabele (man bash), in plaats van de waarde van de variabele te testen.

[[ -v foo ]]; echo $?
# 1
foo=bar
[[ -v foo ]]; echo $?
# 0
foo=""
[[ -v foo ]]; echo $?
# 0

Deze benadering veroorzaakt met name geen fout wanneer deze wordt gebruikt om te controleren op een niet-ingestelde variabele in de modus set -u/ set -o nounset, in tegenstelling tot veel andere benaderingen, zoals het gebruik van [ -z.


Antwoord 5, autoriteit 7%

Er zijn veel manieren om dit te doen, waaronder de volgende:

if [ -z "$1" ]

Dit lukt als $1 null of niet is ingesteld


Antwoord 6, autoriteit 4%

Ik vind de POSIX-tabel in het andere antwoordaltijd traag, dus hier is mijn mening:

  +----------------------+------------+-----------------------+-----------------------+
   |   if VARIABLE is:    |    set     |         empty         |        unset          |
   +----------------------+------------+-----------------------+-----------------------+
 - |  ${VARIABLE-default} | $VARIABLE  |          ""           |       "default"       |
 = |  ${VARIABLE=default} | $VARIABLE  |          ""           | $(VARIABLE="default") |
 ? |  ${VARIABLE?default} | $VARIABLE  |          ""           |       exit 127        |
 + |  ${VARIABLE+default} | "default"  |       "default"       |          ""           |
   +----------------------+------------+-----------------------+-----------------------+
:- | ${VARIABLE:-default} | $VARIABLE  |       "default"       |       "default"       |
:= | ${VARIABLE:=default} | $VARIABLE  | $(VARIABLE="default") | $(VARIABLE="default") |
:? | ${VARIABLE:?default} | $VARIABLE  |       exit 127        |       exit 127        |
:+ | ${VARIABLE:+default} | "default"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

Merk op dat elke groep (met en zonder voorafgaande dubbele punt) dezelfde seten unsetgevallen heeft, dus het enige dat verschilt is hoe de emptyzaken worden afgehandeld.

Met de voorgaande dubbele punt zijn de emptyen unsetgevallen identiek, dus ik zou die waar mogelijk gebruiken (dwz gebruik :=, niet alleen =, omdat de lege hoofdletter niet consistent is).

Koppen:

  • setbetekent dat VARIABLEniet leeg is (VARIABLE="something")
  • leegbetekent dat VARIABLEleeg/null is (VARIABLE="")
  • unsetbetekent dat VARIABLEniet bestaat (unset VARIABLE)

Waarden:

  • $VARIABLEbetekent dat het resultaat de originele waarde van de variabele is.
  • "default"betekent dat het resultaat de vervangende string was.
  • ""betekent dat het resultaat null is (een lege tekenreeks).
  • exit 127betekent dat het script stopt met uitvoeren met exit code 127.
  • $(VARIABLE="default")betekent dat het resultaat "default"enis dat VARIABLE( eerder leeg of niet ingesteld) wordt ook gelijk gesteld aan "default".

Antwoord 7, autoriteit 2%

Om te zien of een variabele niet leeg is, gebruik ik

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

Het tegenovergestelde test of een variabele niet is ingesteld of leeg is:

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

Om te zien of een variabele is ingesteld (leeg of niet-leeg), gebruik ik

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

Het tegenovergestelde test of een variabele niet is ingesteld:

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments

Antwoord 8

Op een moderne versie van Bash (4.2 of later denk ik; ik weet het niet zeker), zou ik dit proberen:

if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil
then
    echo "Variable is unset"
elif [ -z "$SOMEVARIABLE" ]
then
    echo "Variable is set to an empty string"
else
    echo "Variable is set to some string"
fi

Antwoord 9

Opmerking

Ik geef een sterk Bash-gericht antwoord vanwege de bash-tag.

Kort antwoord

Zolang je alleen te maken hebt met benoemde variabelen in Bash, zou deze functie je altijd moeten vertellen of de variabele is ingesteld, zelfs als het een lege array is.

variable-is-set() {
    declare -p "$1" &>/dev/null
}

Waarom dit werkt

In Bash (tenminste zo ver terug als 3.0), als vareen gedeclareerde/set variabele is, dan geeft declare -p vareen declarecommando dat variabele varzou instellen op wat het huidige type en waarde ook is, en statuscode 0retourneert (succes). Als varniet gedeclareerd is, dan stuurt declare -p vareen foutmelding naar stderren retourneert statuscode 1. Met behulp van &>/dev/nullwordt zowel de normale stdout– als de stderr-uitvoer omgeleid naar /dev/null, nooit te zien, en zonder de statuscode te wijzigen. De functie retourneert dus alleen de statuscode.

Waarom andere methoden (soms) mislukken in Bash

  • [ -n "$var" ]:Dit controleert alleen of ${var[0]}niet leeg is. (In Bash is $varhetzelfde als ${var[0]}.)
  • [ -n "${var+x}" ]:Dit controleert alleen of ${var[0]}is ingesteld .
  • [ "${#var[@]}" != 0 ]:Dit controleert alleen of ten minste één index van $varis ingesteld.

Als deze methode faalt in Bash

Dit werkt alleen voor benoemde variabelen (inclusief $_), niet voor bepaalde speciale variabelen ($!, $@, $#, $$, $*, $?, $-, $0, $1, $2, …, en alles wat ik ben vergeten). Aangezien dit geen arrays zijn, werkt de POSIX-stijl [ -n "${var+x}" ]voor al deze speciale variabelen. Maar pas op dat u het niet in een functie wikkelt, aangezien veel speciale variabelen waarden/bestaan ​​veranderen wanneer functies worden aangeroepen.

Opmerking over Shell-compatibiliteit

Als je script arrays heeft en je probeert het compatibel te maken met zoveel mogelijk shells, overweeg dan om typeset -pte gebruiken in plaats van declare -p. Ik heb gelezen dat ksh alleen de eerste ondersteunt, maar ik heb dit niet kunnen testen. Ik weet wel dat Bash 3.0+ en Zsh 5.5.1 beide zowel typeset -pals declare -pondersteunen, waarbij alleen verschilt waarin de ene een alternatief is voor de andere. Maar ik heb geen verschillen getest die verder gaan dan die twee trefwoorden, en ik heb geen andere shells getest.

Als je script POSIX sh-compatibel moet zijn, kun je geen arrays gebruiken. Zonder arrays werkt [ -n "{$var+x}" ].

Vergelijkingscode voor verschillende methoden in Bash

Deze functie schakelt variabele varuit, evalis de doorgegeven code, voert tests uit om te bepalen of varis ingesteld door de evald code, en toont tenslotte de resulterende statuscodes voor de verschillende tests.

Ik sla test -v var, [ -v var ]en [[ -v var ]]over omdat ze opleveren identieke resultaten als de POSIX-standaard [ -n "${var+x}" ], terwijl Bash 4.2+ vereist is. Ik sla ook typeset -pover omdat het hetzelfde is als declare -pin de shells die ik heb getest (Bash 3.0 t/m 5.0 en Zsh 5.5.1).

is-var-set-after() {
    # Set var by passed expression.
    unset var
    eval "$1"
    # Run the tests, in increasing order of accuracy.
    [ -n "$var" ] # (index 0 of) var is nonempty
    nonempty=$?
    [ -n "${var+x}" ] # (index 0 of) var is set, maybe empty
    plus=$?
    [ "${#var[@]}" != 0 ] # var has at least one index set, maybe empty
    count=$?
    declare -p var &>/dev/null # var has been declared (any type)
    declared=$?
    # Show test results.
    printf '%30s: %2s %2s %2s %2s\n' "$1" $nonempty $plus $count $declared
}

Testcasecode

Houd er rekening mee dat testresultaten onverwacht kunnen zijn omdat Bash niet-numerieke array-indices als “0” behandelt als de variabele niet als een associatieve array is gedeclareerd. Ook zijn associatieve arrays alleen geldig in Bash 4.0+.

# Header.
printf '%30s: %2s %2s %2s %2s\n' "test" '-n' '+x' '#@' '-p'
# First 5 tests: Equivalent to setting 'var=foo' because index 0 of an
# indexed array is also the nonindexed value, and non-numerical
# indices in an array not declared as associative are the same as
# index 0.
is-var-set-after "var=foo"                        #  0  0  0  0
is-var-set-after "var=(foo)"                      #  0  0  0  0
is-var-set-after "var=([0]=foo)"                  #  0  0  0  0
is-var-set-after "var=([x]=foo)"                  #  0  0  0  0
is-var-set-after "var=([y]=bar [x]=foo)"          #  0  0  0  0
# '[ -n "$var" ]' fails when var is empty.
is-var-set-after "var=''"                         #  1  0  0  0
is-var-set-after "var=([0]='')"                   #  1  0  0  0
# Indices other than 0 are not detected by '[ -n "$var" ]' or by
# '[ -n "${var+x}" ]'.
is-var-set-after "var=([1]='')"                   #  1  1  0  0
is-var-set-after "var=([1]=foo)"                  #  1  1  0  0
is-var-set-after "declare -A var; var=([x]=foo)"  #  1  1  0  0
# Empty arrays are only detected by 'declare -p'.
is-var-set-after "var=()"                         #  1  1  1  0
is-var-set-after "declare -a var"                 #  1  1  1  0
is-var-set-after "declare -A var"                 #  1  1  1  0
# If 'var' is unset, then it even fails the 'declare -p var' test.
is-var-set-after "unset var"                      #  1  1  1  1

Testoutput

De geheugensteuntjes in de kopregel komen overeen met [ -n "$var" ], [ -n "${var+x}" ], [ "${#var[@]}" != 0 ], en declare -p var, respectievelijk.

                        test: -n +x #@ -p
                      var=foo:  0  0  0  0
                    var=(foo):  0  0  0  0
                var=([0]=foo):  0  0  0  0
                var=([x]=foo):  0  0  0  0
        var=([y]=bar [x]=foo):  0  0  0  0
                       var='':  1  0  0  0
                 var=([0]=''):  1  0  0  0
                 var=([1]=''):  1  1  0  0
                var=([1]=foo):  1  1  0  0
declare -A var; var=([x]=foo):  1  1  0  0
                       var=():  1  1  1  0
               declare -a var:  1  1  1  0
               declare -A var:  1  1  1  0
                    unset var:  1  1  1  1

Samenvatting

  • declare -p var &>/dev/nullis (100%?) betrouwbaar voor het testen van benoemde variabelen in Bash sinds ten minste 3.0.
  • [ -n "${var+x}" ]is betrouwbaar in POSIX-compatibele situaties, maar kan geen arrays aan.
  • Er bestaan ​​andere tests om te controleren of een variabele niet leeg is en om te controleren op gedeclareerde variabelen in andere shells. Maar deze tests zijn niet geschikt voor Bash- of POSIX-scripts.

Antwoord 10

if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

Hoewel het voor argumenten normaal gesproken het beste is om $# te testen, wat het aantal argumenten is, naar mijn mening.

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

Antwoord 11

Je wilt afsluiten als het niet is ingesteld

Dit werkte voor mij. Ik wilde dat mijn script zou afsluiten met een foutmelding als er geen parameter was ingesteld.

#!/usr/bin/env bash
set -o errexit
# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

Dit keert terug met een fout wanneer het wordt uitgevoerd

peek@peek:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

Alleen controleren, geen uitgang – Leeg en Uitgeschakeld zijn ONGELDIG

Probeer deze optie als u alleen wilt controleren of de waarde set=VALID of unset/empty=INVALID.

TSET="good val"
TEMPTY=""
unset TUNSET
if [ "${TSET:- }" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:- }" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:- }" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

Of zelfs korte tests 😉

[ "${TSET:- }"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:- }" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:- }" ] && echo "VALID" || echo "INVALID"

Alleen controleren, niet afsluiten – Alleen leeg is ONGELDIG

En dit is het antwoord op de vraag.
Gebruik dit als u alleen wilt controleren of de waarde set/empty=VALID of unset=INVALID.

OPMERKING, de “1” in “..-1}” is onbeduidend,
het kan van alles zijn (zoals x)

TSET="good val"
TEMPTY=""
unset TUNSET
if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

Korte tests

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

Ik draag dit antwoord op aan @mklement0 (commentaar) die me heeft uitgedaagd om de vraag nauwkeurig te beantwoorden.

Referentie http://pubs.opengroup .org/onlinepubs/96999199799/utilities/V3_chap02.html#tag_18_06_02


Antwoord 12

Voor degenen die willen controleren op uitgeschakeld of leegin een script met set -u:

if [ -z "${var- }" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

De reguliere [ -z "$var" ]controle zal mislukken met var; unbound variableindien set -umaar [ -z "${var- }" ]vouwt uitnaar lege tekenreeks als varis uitgeschakeld zonder te falen.


Antwoord 13

Lees de sectie “Parameteruitbreiding” van de bash-manpagina. Parameteruitbreiding biedt geen algemene test voor een variabele die wordt ingesteld, maar er zijn verschillende dingen die u met een parameter kunt doen als deze niet is ingesteld.

Bijvoorbeeld:

function a {
    first_arg=${1-foo}
    # rest of the function
}

zet first_arggelijk aan $1als het is toegewezen, anders gebruikt het de waarde “foo”. Als aabsoluut een enkele parameter moet hebben en er geen goede standaard bestaat, kunt u afsluiten met een foutmelding als er geen parameter is opgegeven:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(Let op het gebruik van :als een null-commando, dat alleen de waarden van zijn argumenten uitbreidt. We willen in dit voorbeeld niets doen met $1, sluit gewoon af als het niet is ingesteld)


Antwoord 14

Om te controleren of een variabele is ingesteld met een niet-lege waarde, gebruikt u [ -n "$x" ], zoals anderen al hebben aangegeven.

Meestal is het een goed idee om een ​​variabele met een lege waarde op dezelfde manier te behandelen als een variabele die niet is ingesteld. Maar je kunt de twee onderscheiden als dat nodig is: [ -n "${x+set}" ]("${x+set}"breidt uit naar setin als xis ingesteld en op de lege tekenreeks als xniet is ingesteld).

Om te controleren of een parameter is doorgegeven, test $#. Dit is het aantal parameters dat is doorgegeven aan de functie (of aan het script, als deze niet in een functie zit) (zie Pauls antwoord).


Antwoord 15

In bash kun je -vgebruiken in de ingebouwde [[ ]]:

#! /bin/bash -u
if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi
echo $SOMEVAR

Antwoord 16

Samenvatting

  • Gebruik test -n "${var- }"om te controleren of de variabele niet leeg is (en daarom ook gedefinieerd/ingesteld moet worden). Gebruik:

    if test -n "${name- }"; then
      echo "name is set to $name"
    else
      echo "name is not set or empty"
    fi
    
  • Gebruik test ! -z "${var+}"om te controleren of de variabele is gedefinieerd/ingesteld (zelfs als deze leeg is). Gebruik:

    if test ! -z "${var+}"; then
      echo "name is set to $name"
    else
      echo "name is not set"
    fi
    

Houd er rekening mee dat het eerste gebruik veel vaker voorkomt in shellscripts en dit is wat u meestal wilt gebruiken.

Opmerkingen

  • Deze oplossing zou in alle POSIX-shells moeten werken (sh, bash, zsh, ksh, dash)
  • Sommige van de andere antwoorden op deze vraag zijn correct, maar kunnen verwarrend zijn voor mensen die geen ervaring hebben met shellscripting, dus ik wilde een TLDR-antwoord geven dat voor zulke mensen het minst verwarrend zal zijn.

Uitleg

Om te begrijpen hoe deze oplossing werkt, moet u de POSIX testcommandoen POSIX shell parameteruitbreiding (spec ), dus laten we de absolute basis bespreken die nodig is om het antwoord te begrijpen.

Het testcommando evalueert een expressie en retourneert true of false (via de exit-status). De operator -nretourneert waar als de operand een niet-lege tekenreeks is. Dus bijvoorbeeld, test -n "a"retourneert true, terwijl test -n ""false retourneert. Om nu te controleren of een variabele niet leeg is (wat betekent dat deze gedefinieerd moet worden), zou je test -n "$var"kunnen gebruiken. Sommige shellscripts hebben echter een optieset (set -u) die ervoor zorgt dat elke verwijzing naar niet-gedefinieerde variabelen een fout geeft, dus als de variabele varniet is gedefinieerd, wordt de uitdrukking $azal een fout veroorzaken. Om dit geval correct af te handelen, moet je variabele expansie gebruiken, die de shell zal vertellen om de variabele te vervangen door een alternatieve string als deze niet gedefinieerd is, om de bovengenoemde fout te vermijden.

De variabele uitbreiding ${var- }betekent: als de variabele varniet gedefinieerd is (ook wel “unset” genoemd), vervang deze dan door een lege string. Dus test -n "${var- }"zal true retourneren als $varniet leeg is, wat bijna altijd is wat je wilt controleren in shellscripts. De omgekeerde controle, als $varniet gedefinieerd is of niet leeg is, zou test -z "${var- }"zijn.

Nu naar de tweede use case: controleren of de variabele varis gedefinieerd, leeg of niet. Dit komt minder vaak voor en is iets complexer, en ik raad je aan om het geweldige antwoord van Lionelste lezen om het beter te begrijpen. .


Antwoord 17

Het gebruik van [[ -z "$var" ]]is de gemakkelijkste manier om te weten of een variabele is ingesteld of niet, maar die optie -zniet onderscheid maken tussen een uitgeschakelde variabele en een variabele die is ingesteld op een lege tekenreeks:

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

Het is het beste om het te controleren op het type variabele: env variabele, parameter of reguliere variabele.

Voor een env-variabele:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

Voor een parameter (bijvoorbeeld om het bestaan ​​van parameter $5te controleren):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

Voor een reguliere variabele (met behulp van een hulpfunctie, om het op een elegante manier te doen):

function declare_var {
   declare -p "$1" &> /dev/null
}
declare_var "var_name" && echo "Set" || echo "Unset"

Opmerkingen:

  • $#:geeft je het aantal positionele parameters.
  • declare -p:geeft je de definitie van de variabele die als parameter is doorgegeven. Als het bestaat, retourneert 0, zo niet, retourneert 1 en drukt een foutmelding af.
  • &> /dev/null:onderdrukt de uitvoer van declare -pzonder de retourcode te beïnvloeden.

Antwoord 18

Om de vraag van OP over hoe te bepalen of een variabele is ingesteld duidelijk te beantwoorden, is het antwoord van @Lionel correct:

if test "${name+x}"; then
    echo 'name is set'
else
    echo 'name is not set'
fi

Deze vraag heeft al veel antwoorden, maar geen van hen bood bonafidebooleaanse uitdrukkingen om duidelijk onderscheid te maken tussen waarden van variabelen.

Hier zijn enkele ondubbelzinnige uitdrukkingen die ik heb uitgewerkt:

+-----------------------+-------------+---------+------------+
| Expression in script  | name='fish' | name='' | unset name |
+-----------------------+-------------+---------+------------+
| test "$name"          | TRUE        | f       | f          |
| test -n "$name"       | TRUE        | f       | f          |
| test ! -z "$name"     | TRUE        | f       | f          |
| test ! "${name-x}"    | f           | TRUE    | f          |
| test ! "${name+x}"    | f           | f       | TRUE       |
+-----------------------+-------------+---------+------------+

Trouwens, deze uitdrukkingen zijn equivalent:
test <expression><=> [ <expression> ]

Andere dubbelzinnige uitdrukkingen die voorzichtig moeten worden gebruikt:

+----------------------+-------------+---------+------------+
| Expression in script | name='fish' | name='' | unset name |
+----------------------+-------------+---------+------------+
| test "${name+x}"     | TRUE        | TRUE    | f          |
| test "${name-x}"     | TRUE        | f       | TRUE       |
| test -z "$name"      | f           | TRUE    | TRUE       |
| test ! "$name"       | f           | TRUE    | TRUE       |
| test ! -n "$name"    | f           | TRUE    | TRUE       |
| test "$name" = ''    | f           | TRUE    | TRUE       |
+----------------------+-------------+---------+------------+

Antwoord 19

U kunt het volgende doen:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

Antwoord 20

De bovenstaande antwoorden werken niet als de Bash-optie set -uis ingeschakeld. Ze zijn ook niet dynamisch, bijvoorbeeld hoe te testen is variabel met de naam “dummy” is gedefinieerd? Probeer dit:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:- }" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from $1 as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${$1:- }" ].  We need to use indirection with eval operator.
    # Example: $1="var"
    # Expansion for eval operator: "[ ! -z \${$1:- } ]" -> "[ ! -z \${var:- } ]"
    # Code  execute: [ ! -z ${var:- } ]
    eval "[ ! -z \${$1:- } ]"
    return $?  # Pedantic.
}

Gerelateerd: Hoe test ik in Bash of een variabele is gedefinieerd in de “-u”-modus


Antwoord 21

Mijn favoriete manier is deze:

$ var=10
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$ unset -v var
$ if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

Dus in principe, als een variabele is ingesteld, wordt deze “een ontkenning van de resulterende false” (wat zal true= “is ingesteld”).

p>

En als het niet is ingesteld, wordt het “een negatie van de resulterende true” (aangezien het lege resultaat evalueert tot true) (dus eindigt als false= “NIET ingesteld”).


Antwoord 22

Dit is wat ik elke dag gebruik:

#
# Check if a variable is set
#   param1  name of the variable
#
function is_set() { [[ $(eval echo "\${${1}+x}") ]]; }

Dit werkt goed onder Linux en Solaris tot bash 3.0.

bash-3.00$ myvar="TEST"
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ myvar=
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ unset myvar
bash-3.00$ is_set myvar ; echo $?
1

Antwoord 23

Het verbaast me dat niemand heeft geprobeerd een shellscript te schrijven om programmatisch de beruchte moeilijk te grok-tabelte genereren. Aangezien we hier coderingstechnieken proberen te leren, waarom zou u het antwoord dan niet in code uitdrukken? 🙂 Dit is mijn mening (zou moeten werken in elke POSIX-shell):

H="+-%s-+-%s----+-%s----+-%s--+\n"       # table divider printf format
R="| %-10s | %-10s | %-10s | %-10s |\n"  # table row printf format
S='V'     # S is a variable that is set-and-not-null
N=''      # N is a variable that is set-but-null (empty "")
unset U   # U is a variable that is unset
printf "$H" "----------" "-------" "-------" "---------";
printf "$R" "expression" "FOO='V'" "FOO='' " "unset FOO";
printf "$H" "----------" "-------" "-------" "---------";
printf "$R" "\${FOO:-x}" "${S:-x}" "${N:-x}" "${U:-x}  "; S='V';N='';unset U
printf "$R" "\${FOO-x} " "${S-x} " "${N-x} " "${U-x}   "; S='V';N='';unset U
printf "$R" "\${FOO:=x}" "${S:=x}" "${N:=x}" "${U:=x}  "; S='V';N='';unset U
printf "$R" "\${FOO=x} " "${S=x} " "${N=x} " "${U=x}   "; S='V';N='';unset U
printf "$R" "\${FOO:?x}" "${S:?x}" "<error>" "<error>  "; S='V';N='';unset U
printf "$R" "\${FOO?x} " "${S?x} " "${N?x} " "<error>  "; S='V';N='';unset U
printf "$R" "\${FOO:+x}" "${S:+x}" "${N:+x}" "${U:+x}  "; S='V';N='';unset U
printf "$R" "\${FOO+x} " "${S+x} " "${N+x} " "${U+x}   "; S='V';N='';unset U
printf "$H" "----------" "-------" "-------" "---------";
# For reference, the following two lines are the literal rows of the table
# which would cause the script to exit and so have had <error> written in.
#printf "$R" "\${FOO:?x}" "${S:?x}" "${N:?x}" "${U:?x}  "; S='V';N='';unset U
#printf "$R" "\${FOO?x} " "${S?x} " "${N?x} " "${U?x}   "; S='V';N='';unset U

En de uitvoer van het uitvoeren van het script:

+------------+------------+------------+------------+
| expression | FOO='V'    | FOO=''     | unset FOO  |
+------------+------------+------------+------------+
| ${FOO:-x}  | V          | x          | x          |
| ${FOO-x}   | V          |            | x          |
| ${FOO:=x}  | V          | x          | x          |
| ${FOO=x}   | V          |            | x          |
| ${FOO:?x}  | V          | <error>    | <error>    |
| ${FOO?x}   | V          |            | <error>    |
| ${FOO:+x}  | x          |            |            |
| ${FOO+x}   | x          | x          |            |
+------------+------------+------------+------------+

Het script mist een paar functies, zoals weergeven wanneer de neveneffecttoewijzingen wel (of niet) plaatsvinden, maar misschien wil een andere, meer ambitieuze persoon dit uitgangspunt nemen en ermee aan de slag gaan.


Antwoord 24

[[ $foo ]]

Of

(( ${#foo} ))

Of

let ${#foo}

Of

declare -p foo

Antwoord 25

In een shell kun je de operator -zgebruiken, die True is als de lengte van de string nul is.

Een eenvoudige one-liner om de standaard MY_VARin te stellen als deze niet is ingesteld, anders kunt u optioneel het bericht weergeven:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

Antwoord 26

Om te testen of een variabele varis ingesteld: [ ${var+x} ].

Om te testen of een variabele op naam is ingesteld: [ ${!name+x} ].

Om te testen of een positionele parameter is ingesteld: [ ${N+x} ], waarbij N eigenlijk een geheel getal is.

Dit antwoord lijkt bijna op dat van Lionel, maar verken een meer minimalistische versie door de -zweg te laten.

Om te testen of een benoemde variabele is ingesteld :

function is_set {
    local v=$1
    echo -n "${v}"
    if [ ${!v+x} ]; then
        echo " = '${!v}'"
    else
        echo " is unset"
    fi
}

Om te testen of een positionele parameter is ingesteld :

function a {
    if [ ${1+x} ]; then
        local arg=$1
        echo "a '${arg}'"
    else
        echo "a: arg is unset"
    fi
}

Uit testen blijkt dat extra voorzichtigheid met spaties en geldige testuitdrukkingen niet nodig is.

set -eu
V1=a
V2=
V4=-gt
V5="1 -gt 2"
V6="! -z 1"
V7='$(exit 1)'
is_set V1
is_set V2
is_set V3
is_set V4
is_set V5
is_set V6
is_set V7
a 1
a
a "1 -gt 2"
a 1 -gt 2
$./test.sh 
V1 = 'a'
V2 = ''
V3 is unset
V4 = '-gt'
V5 = '1 -gt 2'
V6 = '! -z 1'
V7 = '$(exit 1)'
a '1'
a: arg is unset
a '1 -gt 2'
a '1'

Let ten slotte op de set -eudie ons beschermt tegen veelvoorkomende fouten, zoals typefouten in variabelenamen. Ik raad het gebruik ervan aan, maar dit houdt in dat het verschil tussen een uitgeschakelde variabele en een variabele die is ingesteld met een lege tekenreeks correct wordt afgehandeld.


Antwoord 27

if [[ ${1:+isset} ]]
then echo "It was set and not null." >&2
else echo "It was not set or it was null." >&2
fi
if [[ ${1+isset} ]]
then echo "It was set but might be null." >&2
else echo "It was was not set." >&2
fi

Antwoord 28

Ik heb een (veel) betere code gevonden om dit te doen als je iets wilt controleren in $@.

if [[ $1 = "" ]]
dan
 echo '$1 is leeg'
anders
 echo '$1 is vol'
fi

Waarom dit allemaal? Alles in $@bestaat in Bash, maar is standaard leeg, dus test -zen test -nkonden je niet helpen.

Update:u kunt ook het aantal tekens in een parameter tellen.

if [ ${#1} = 0 ]
dan
 echo '$1 is leeg'
anders
 echo '$1 is vol'
fi

Antwoord 29

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

Antwoord 30

Ik hou van hulpfuncties om de ruwe details van bash te verbergen. In dit geval voegt dit nog meer (verborgen) ruwheid toe:

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname="$1"
  ! [ -z ${!varname+x} ]
}

Omdat ik voor het eerst bugs had in deze implementatie (geïnspireerd door de antwoorden van Jens en Lionel), kwam ik met een andere oplossing:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

Ik vind het meer rechttoe rechtaan, bashy en gemakkelijker te begrijpen/onthouden. Testcase laat zien dat het equivalent is:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''
  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"
  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}
main

De testcase laat ook zien dat local varNIETvar declareert (tenzij gevolgd door ‘=’). Ik dacht al geruime tijd dat ik variabelen op deze manier had gedeclareerd, alleen om te ontdekken dat ik nu alleen maar mijn bedoeling heb uitgedrukt… Het is een no-op, denk ik.

IsDeclared_Tricky xyz: 1
IsDeclared_Tricky foo: 1
IsDeclared_Tricky balk: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
IsDeclared foo: 1
IsDeclared-balk: 0
IsDeclared baz: 0

BONUS: gebruiksvoorbeeld

Ik gebruik deze test meestal om parameters aan functies te geven (en terug te geven) op een enigszins“elegante” en veilige manier (die bijna op een interface lijkt…):

#auxiliary functions
function die()
{
  echo "Error: $1"; exit 1
}
function assertVariableDeclared()
{
  IsDeclared "$1" || die "variable not declared: $1"
}
function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared $1; shift
  done
}
# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}
function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}
bonus

Indien aangeroepen met all vereist gedeclareerde variabelen:

Hallo wereld!

anders:

Fout: variabele niet gedeclareerd: outputStr

LEAVE A REPLY

Please enter your comment!
Please enter your name here

sixteen − thirteen =

Other episodes