Wie kann ich testen, ob eine Variable leer ist oder nur Leerzeichen enthält?

Die folgende Bash-Syntax überprüft, ob param nicht „leer“ ist:

 [[ ! -z $param ]] 

Zum Beispiel:

param="" [[ ! -z $param ]] && echo "I am not zero" 

Keine Ausgabe und es ist in Ordnung.

Aber wenn param ist bis auf ein (oder mehrere) Leerzeichen leer, dann ist der Fall anders:

param=" " # one space [[ ! -z $param ]] && echo "I am not zero" 

„Ich bin nicht Null „wird ausgegeben.

Wie kann ich den Test ändern, um Variablen, die nur Leerzeichen enthalten, als leer zu betrachten?

Kommentare

  • Von man test: -z STRING - the length of STRING is zero. Wenn Sie alle Leerzeichen in $param entfernen möchten, Verwenden Sie ${param// /}
  • WOW Es ist keine einfache trim() -Funktion integriert Irgendwelche * nix überhaupt? So viele verschiedene Hacks, um etwas so Einfaches zu erreichen …
  • @ADTC $ (sed ‚ s / ^ \ s + | \ s + $ // g ‚ < < < $ string) scheint mir einfach zu sein. Warum das Rad neu erfinden?
  • Weil es glänzender sein könnte
  • Nur zu beachten, dass [[ ! -z $param ]] test ! -z $param.

Antwort

Beachten Sie zunächst, dass die -z Test ist explizit für:

Die Länge der Zeichenfolge ist Null

Das heißt, eine Zeichenfolge, die nur Leerzeichen enthält, sollte nicht ist unter -z wahr, da es eine Länge ungleich Null hat.

Sie möchten die Leerzeichen mit der Erweiterung der Musterersetzungsparameter :

[[ -z "${param// }" ]] 

Dies erweitert die param variabel und ersetzt alle Übereinstimmungen des Musters (ein einzelnes Leerzeichen) durch nichts, sodass eine Zeichenfolge, die nur Leerzeichen enthält, zu einem erweitert wird leere Zeichenfolge.


Die , wie das funktioniert ist, dass ${var/pattern/string} ersetzt die erste längste Übereinstimmung von pattern durch string. Wenn pattern mit / (wie oben) beginnt, werden alle Übereinstimmungen ersetzt. Da der Ersatz leer ist, können wir den endgültigen Wert / und den Wert string weglassen:

$ {parameter / pattern / string}

Das pattern wird erweitert, um ein Muster wie bei der Dateinamenerweiterung zu erzeugen. Parameter wird erweitert und die längste Übereinstimmung von Muster mit seinem Wert wird durch Zeichenfolge ersetzt. Wenn pattern mit „/“ beginnt, werden alle Übereinstimmungen von pattern durch string ersetzt. Normalerweise wird nur das erste Spiel ersetzt. … Wenn string null ist, werden Übereinstimmungen von pattern gelöscht und das / folgende pattern kann weggelassen werden.

Nach all dem haben wir ${param// }, um alle Leerzeichen zu löschen.

Beachten Sie dies jedoch vorhanden in ksh (woher es stammt), zsh und bash ist diese Syntax nicht vorhanden POSIX und sollte nicht in sh -Skripten verwendet werden.

Kommentare

  • use sed sagten sie … nur echo die Variable, die sie sagten …
  • Hmm. Wenn es ${var/pattern/string} ist, sollte ‚ nicht [[ -z ${param/ /} ]] mit dem Abstand zwischen den Schrägstrichen sein um das Muster und nichts danach die Zeichenfolge zu sein?
  • @JesseChisholm “ Da die Ersetzung leer ist, können wir das endgültige / und den Zeichenfolgenwert „; “ Wenn string null ist, werden Übereinstimmungen von pattern gelöscht und das / folgende pattern kann sein weggelassen. “
  • @MichaelHomer Die Antwort [[ -z "${param// }" ]] sieht sicher aus wie die pattern ist leer und die replacement string ist ein einzelnes Leerzeichen. AH! Ich sehe es jetzt if pattern begins with a slash Ich habe diesen Teil verpasst. Das Muster lautet also / , und die Zeichenfolge wird weggelassen und ist daher leer. Danke.
  • Bash-Hinweis: Wenn in set -o nounset (set -u) ausgeführt wird und param nicht gesetzt ist (anstatt null oder mit Leerzeichen gefüllt), wird ein ungebundener Variablenfehler generiert. (set + u; …..) würde diesen Test ausnehmen.

Antwort

Der einfache Weg Um zu überprüfen, ob eine Zeichenfolge nur Zeichen in einem autorisierten Satz enthält, müssen Sie prüfen, ob nicht autorisierte Zeichen vorhanden sind.Anstatt zu testen, ob die Zeichenfolge nur Leerzeichen enthält, testen Sie daher, ob die Zeichenfolge ein anderes Zeichen als Leerzeichen enthält. In bash, ksh oder zsh:

if [[ $param = *[!\ ]* ]]; then echo "\$param contains characters other than space" else echo "\$param consists of spaces only" fi 

„Besteht nur aus Leerzeichen“ enthält den Fall einer leeren (oder nicht gesetzten) Variablen.

Möglicherweise möchten Sie nach Leerzeichen suchen. Verwenden Sie [[ $param = *[^[:space:]]* ]], um die Gebietsschemaeinstellungen oder eine explizite Liste von Leerzeichen zu verwenden, auf die Sie testen möchten, z. [[ $param = *[$" \t\n"]* ]] zum Testen auf Leerzeichen, Tabulator oder Zeilenumbruch.

Abgleichen eines Strings mit einem Muster mit = innerhalb von [[ … ]] ist eine ksh-Erweiterung (auch in bash und zsh vorhanden). In jedem Bourne / POSIX-Stil können Sie das Konstrukt case verwenden, um eine Zeichenfolge mit einem Muster abzugleichen. Beachten Sie, dass Standard-Shell-Muster ! verwenden, um einen Zeichensatz zu negieren, anstatt ^ wie in den meisten Syntaxen für reguläre Ausdrücke.

case "$param" in *[!\ ]*) echo "\$param contains characters other than space";; *) echo "\$param consists of spaces only";; esac 

Zum Testen auf Leerzeichen ist die Syntax $"…" spezifisch für ksh / bash / zsh. Sie können diese Zeichen buchstäblich in Ihr Skript einfügen (beachten Sie, dass eine neue Zeile in Anführungszeichen stehen muss, da Backslash + Newline zu nichts erweitert wird) oder sie generieren, z. B.

whitespace=$(printf "\n\t ") case "$param" in *[!$whitespace]*) echo "\$param contains non-whitespace characters";; *) echo "\$param consists of whitespace only";; esac 

Kommentare

  • Dies ist fast ausgezeichnet – aber es beantwortet die gestellte Frage noch nicht. Derzeit können Sie den Unterschied zwischen einer nicht gesetzten oder leeren Shell-Variablen und einer Variablen erkennen, die nur Leerzeichen enthält. Wenn Sie meinen Vorschlag akzeptieren, fügen Sie das Parametererweiterungsformular hinzu, das noch nicht von einer anderen Antwort konvergiert wurde, die explizit eine Shell-Variable auf ihre Einstellung testet – ich meine ${var?not set} – diesen Test besteht und überlebt würde sicherstellen, dass eine Variable, die mit Ihrer *) case übereinstimmt, beispielsweise eine endgültige Antwort bewirkt.
  • Korrektur – Dies würde in der Tat die ursprünglich gestellte Frage beantworten, wurde jedoch inzwischen so bearbeitet, dass sich die Bedeutung der Frage grundlegend ändert und Ihre Antwort daher ungültig wird.
  • Sie benötigen [[ $param = *[!\ ]* ]] in mksh.

Antwort

POSIXly:

case $var in (*[![:blank:]]*) echo "$var contains non blank";; (*) echo "$var contains only blanks or is empty or unset" esac 

Zur Unterscheidung zwischen blank und non-blank , leer , nicht gesetzt :

case ${var+x$var} in (x) echo empty;; ("") echo unset;; (x*[![:blank:]]*) echo non-blank;; (*) echo blank esac 

[:blank:] steht für Zeichen mit horizontalem Abstand (Leerzeichen und Tabulator in A. SCII, aber es gibt wahrscheinlich noch ein paar mehr in Ihrem Gebietsschema; Einige Systeme enthalten den nicht unterbrechenden Bereich (sofern verfügbar), andere nicht „t“. Wenn Sie auch Zeichen mit vertikalem Abstand (wie Zeilenumbruch oder Formularvorschub) möchten, ersetzen Sie [:blank:] mit [:space:].

Kommentare

  • POSIXly ist ideal, da es mit dem (wohl besseren) funktioniert. dash.
  • zsh scheint ein Problem mit [![:blank:]] zu haben, es löst :b ist ein ungültiger Modifikator. In sh und ksh emulieren wird ein Ereignis ausgelöst, das für [
  • @cuonglm, was haben Sie versucht? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' ist für mich in Ordnung. Das nicht gefundene Ereignis ist nur für interaktive Shells.
  • @St é phaneChazelas: Ah, richtig, ich habe es mit interaktiven Shells versucht. Der ungültige Modifikator :b ist etwas seltsam.
  • @FranklinYu ist unter OS / X sh erstellt mit --enable-xpg-echo-default und --enable-strict-posix-default, um Unix-kompatibel zu sein (was Ausgabe einer Registerkarte).

Antwort

Der einzige verbleibende Grund zum Schreiben Ein Shell-Skript anstelle eines Skripts in einer guten -Skriptsprache ist, wenn extreme Portabilität ein vorrangiges Anliegen ist. Das Legacy /bin/sh ist das einzige, von dem Sie sicher sein können, dass Sie es haben, aber Perl zum Beispiel ist eher plattformübergreifend verfügbar als Bash. Schreiben Sie daher niemals Shell-Skripte, die Funktionen verwenden, die nicht wirklich universell sind – und denken Sie daran, dass mehrere proprietäre Unix-Anbieter ihre Shell-Umgebung vor POSIX.1-2001 .

Es gibt eine tragbare Möglichkeit, diesen Test durchzuführen, aber Sie müssen tr verwenden:

[ "x`printf "%s" "$var" | tr -d "$IFS"`" = x ] 

(Der Standardwert von $IFS ist zweckmäßigerweise ein Leerzeichen, eine Registerkarte und eine neue Zeile.)

(Die printf integriert ist selbst sehr portabel, aber es ist viel weniger mühsam, sich darauf zu verlassen, als herauszufinden, welche Variante von echo Sie haben.)

Kommentare

  • Das ‚ ist etwas verworren.Die übliche tragbare Methode zum Testen, ob eine Zeichenfolge bestimmte Zeichen enthält, ist mit case .
  • @ Gilles Ich glaube nicht, dass es ‚ möglich ist, einen case Glob zu schreiben Erkennen Sie eine Zeichenfolge, die entweder leer ist oder nur Leerzeichen enthält. (Mit einem regulären Ausdruck wäre es einfach, aber case führt

keine regulären Ausdrücke aus. Das Konstrukt in Ihrer Antwort wird ‚ funktioniert nicht, wenn Sie sich für Zeilenumbrüche interessieren.)

  • Ich habe in meiner Antwort Leerzeichen als Beispiel angegeben, da ‚ die Frage ist gefragt. ‚ ist ebenso einfach auf Leerzeichen zu testen: case $param in *[![:space:]]*) …. Wenn Sie auf IFS Zeichen testen möchten, können Sie das Muster *[$IFS]* verwenden.
  • @mikeserv In a real ernsthaft defensives Skript, Sie setzen IFS zu Beginn explizit auf <space><tab><newline> und berühren es dann nie wieder. Ich dachte, dass ‚ eine Ablenkung sein würde.
  • In Bezug auf Variablen in Mustern denke ich, dass dies in allen Bourne-Versionen und allen POSIX-Shells funktioniert. Es würde zusätzlichen Code erfordern, um Fallmuster zu erkennen und die Variablenerweiterung zu deaktivieren, und ich kann mir ‚ keinen Grund dafür vorstellen. Ich habe einige Instanzen davon in meiner .profile, die von vielen Bourne-Shells ausgeführt wurde. Natürlich wird [$IFS] ‚ nicht das tun, was beabsichtigt war, wenn IFS bestimmte Nicht-Standardwerte aufweist Werte (leer (oder nicht gesetzt), die ] enthalten, beginnend mit ! oder ^) .
  • Antwort

    if [[ -n "${variable_name/[ ]*\n/}" ]] then #execute if the the variable is not empty and contains non space characters else #execute if the variable is empty or contains only spaces fi 

    Kommentare

    • Dadurch werden alle Leerzeichen entfernt, nicht nur ein einzelnes Leerzeichen, oder? danke

    Antwort

    Zum Testen, ob die Variable leer ist oder Leerzeichen enthält, können Sie auch diesen Code verwenden:

    ${name:?variable is empty} 

    Kommentare

    • Ich denke, Ihre Antwort wurde abgelehnt, weil die “ oder Leerzeichen enthalten “ ist nicht wahr.
    • Seien Sie vorsichtig – das tötet die aktuelle Shell. Besser in eine (: $ {Subshell?}). Außerdem – das wird an stderr geschrieben – möchten Sie wahrscheinlich umleiten. Und am wichtigsten , das den tatsächlichen Wert der Variablen ‚ ergibt, wenn er nicht nicht gesetzt oder null ist. Wenn dort ‚ ein Befehl enthalten ist, haben Sie ihn einfach ausgeführt. ‚ führt diesen Test am besten auf : aus.
    • wie die Shell getötet wird. und Sie können dies auch testen. Definieren Sie zuerst name=aaaa und führen Sie dann diesen Befehl aus. echo ${name:?variable is empty} gibt den Wert des Variablennamens aus und führt nun diesen Befehl echo ${name1:?variable is empty} gibt -sh: name1 aus: Variable ist leer
    • Ja – echo ${name:?variable is empty} wird entweder als $name ‚ als Nicht-Null-Wert ausgewertet oder wird die Shell beenden. Aus dem gleichen Grund tun Sie ‚ nicht prompt > $randomvar und ${var?} – if dort ‚ ist ein Befehl drin, ‚ wird wahrscheinlich ausgeführt – und Sie geben ‚ Ich weiß nicht, was es ist. Eine interaktive Shell muss nicht ‚ beendet werden – weshalb Ihre ‚ t nicht ausgeführt wird. Wenn Sie jedoch einige Tests sehen möchten, gibt es hier viele . . Dieser ist nicht ‚ nicht ganz so lang …

    Antwort

    Der von Ihnen veröffentlichte Code [[ ! -z $param ]] && echo "I am not zero" gibt I am not zero aus, wenn param ist entweder nicht gesetzt / undefiniert oder leer (in bash, ksh und zsh).

    Zu auch print, wenn param nur Leerzeichen enthält (Leerzeichen entfernen), POSIXly (für einen größeren Bereich von Shells):

     [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

    Erläuterung:

    • Ein ${param# … } entfernt einen führenden Text.
    • Dieser führende Text wird gegeben durch: ${param%%[! ]*}
    • Dieser wird auf alle Leerzeichen vor ein beliebiges Nicht-Leerzeichen Zeichen, dh alle führenden Leerzeichen.

    Das Endergebnis der gesamten Erweiterung ist, dass alle führenden Leerzeichen entfernt werden.

    Dieses erweiterte Ergebnis wird auf Länge 0 getestet.

    • Wenn das Ergebnis leer ist, war entweder die Variable leer oder
    • entfernt die führenden Leerzeichen machte es leer.

    Wenn der Test wahr ist, war die Variable entweder bereits leer oder enthielt nur Leerzeichen.


    Das Konzept lässt sich leicht auf weitere erweitern Zeichentypen. Um auch Registerkarten einzuschließen, platzieren Sie eine explizite Registerkarte in dem Klammerausdruck:

     [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

    oder verwenden Sie eine Variable mit den Zeichen, die Sie entfernen müssen:

     var=$" \t" # in ksh, bash, zsh [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty" 

    oder Sie können einen POSIX „Zeichenklassenausdruck“ verwenden (leer bedeutet Leerzeichen und Tabulator):

     [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty" 

    Antwort

    Um zu überprüfen, ob die Variable nur Leerzeichen enthält, einschließlich einer mehrzeiligen Variablen , versuchen Sie Folgendes:

    [[ $var = *[$" \t\n"]* ]] 

    Oder mit xargs:

    [[ -z $(echo $var | xargs) ]] 

    Oder mit sed:

    [[ -z $(sed "/^$/d" <<< $var) ]] 

    Antwort

    Versuchen Sie Folgendes:

    $ [[ -z \`echo $n\` ]] && echo zero zero 

    Schreibe einen Kommentar

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.