1 Punkte von GN⁺ 2 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • : in der Shell ist ein Nullbefehl (null command), der nichts tut und nur seine Argumente auswertet. In Kombination mit Parameter Expansion lassen sich Pflichtargumente prüfen und Standardwerte knapp handhaben
  • : "${1:?missing argument, aborting!}" gibt eine Diagnosemeldung auf stderr aus und beendet sich mit einem Status ungleich 0, wenn $1 fehlt oder leer ist
  • Übergibt man ${VAR:=default} als Argument an :, wird die Expansion ausgeführt, die resultierende Zeichenkette aber verworfen. So lässt sich nur ein Standardwert setzen, ohne das Expansionsergebnis als Befehl auszuführen
  • : kann auch zum Leeren von Dateien per Redirection, zum Prüfen der Zugreifbarkeit, als leerer Befehl in trap, zur Variablenprüfung unter set -u sowie in leeren Bedingungszweigen verwendet werden
  • : "${VAR:=default}" reduziert Tippfehler, weil der Variablenname nur einmal geschrieben wird; in while : ist es eine immer erfolgreiche Bedingung und drückt eine Endlosschleife aus

Nullbefehl und Parameter Expansion

  • : ist ein eingebauter Nullbefehl, der seine Argumente auswertet und das Ergebnis verwirft
    • Er reicht bis zur Thompson shell von 1971 zurück und wurde damals auch als Label sowie als erstes Kommentarzeichen in Unix verwendet
  • Statt eines vierzeiligen Konditionals kann man ein Pflichtargument mit folgender Einzeile prüfen
: "${1:?missing argument, aborting!}"
echo "Hello $1!"
  • Die Syntax ${name:?diagnostic} der Parameter Expansion prüft, ob $name nicht gesetzt oder leer ist
    • Fehlt der Wert, wird diagnostic auf stderr ausgegeben und die Shell mit einem Status ungleich 0 beendet
    • Ist ein Wert vorhanden, liefert sie dasselbe Ergebnis wie $name
  • Führt man ${HELLO:=123} ohne Nullbefehl aus, wird das Expansionsergebnis 123 als Befehl behandelt, was zu command not found führt
    • : ${HELLO:=123} wertet die Expansion aus, setzt dabei HELLO=123 und verwirft das Ergebnis
  • : "${DATA_DIR:=/var/data}" schreibt den Variablennamen im Gegensatz zu DATA_DIR="${DATA_DIR:-/var/data}" nur einmal und reduziert damit die Wahrscheinlichkeit von Tippfehlern wie DATA_DRI

Einsatzmöglichkeiten von :

  • Standardwerte setzen

    • Setzt Standardwerte für Variablen, während das Expansionsergebnis verworfen und nicht ausgeführt wird
: "${DATA_DIR:=/var/data}"
: "${RETRIES:=3}"
  • Dateien leeren und Zugriff prüfen

    • In Kombination mit Redirection lassen sich eine oder mehrere Dateien leeren
: > error.log
: > error.log > access.log
  • Mit einer Subshell und Redirection kann auch geprüft werden, ob Dateien les- bzw. schreibbar sind
( : < dataset.json ) && echo YES
( : >> result.json ) && echo YES
  • Stellen, an denen ein leerer Befehl nötig ist

    • Nützlich, wenn syntaktisch ein Befehl erforderlich ist, aber tatsächlich nichts passieren soll, etwa bei trap
trap : INT
sleep 60
  • Auch in einem absichtlich leeren Zweig einer Bedingung einsetzbar
if some-command; then
    :
else
    echo "command failed"
fi
  • Mehrere Variablen prüfen

    • Prüft bei aktiviertem set -u mehrere Variablen auf einmal darauf, ob sie gesetzt sind
set -u
: "$DEPLOY_ENV" "$HOST"
  • Endlosschleife

    • Da : immer erfolgreich ist, lässt sich eine Endlosschleife knapp schreiben
while :; do
  echo "I love colons"
  sleep 1
done

1 Kommentare

 
GN⁺ 2 시간 전
Lobste.rs-Kommentare
  • Wenn man den Prompt so gestaltet, wird selbst beim Kopieren und Einfügen der ganzen Zeile der Prompt-Teil ignoriert und nur der Befehl ausgeführt
    : hayalci@tassadar ~/src/dool ; jj rebase -s dxw -d mrn
    • Inspiriert von Plan 9 verwende ich auch die autocd-Option der Shell und das folgende Format
      ~/directoryname; <command>
      Beim Kopieren der Shell-Befehlszeile wird dadurch jedes Mal weiter in das Verzeichnis cd gewechselt, in dem der Befehl ursprünglich ausgeführt wurde
    • In zsh ist es so konfiguriert, dass beim Einfügen eines unsichtbaren geschützten Leerzeichens ohne Zeilenumbruch der linke Inhalt gelöscht wird
      nbsp=$'\u00A0'  
      PS1="...$nbsp"  
      bindkey -s $nbsp '^u'  
      
  • In Makefiles verwende ich den Doppelpunkt oft für eine ansehnliche Ausgabe
    out/%.o: src/%.c  
        @echo CC $@  
        @$(CC) -c -o $@ $<  
    
    Bei dieser Methode kann make mehrere echo-Prozesse gleichzeitig starten, die in denselben Stream schreiben und sich dadurch gegenseitig stören. Wenn man es so ändert, gibt nicht ein Kindprozess, sondern der make-Prozess selbst aus
    out/%.o: src/%.c  
        : CC $@  
        @$(CC) -c -o $@ $<  
    
  • Ich habe diese Technik in Shell-Skripten gesehen, aber mit man : oder whatis : war kaum brauchbare Dokumentation zu finden
    Sie ist ähnlich wie der Befehl true, reagiert aber nicht speziell auf --help, --version usw. und hat außerdem weniger Zeichen
    • Bash-Builtins sollte man statt mit man mit help nachschlagen
      $ help :  
      :: :  
          Null command.
      
          No effect; the command does nothing.
      
          Exit Status:  
          Always succeeds.  
      
    • In Fish ist : buchstäblich ein Alias für true
  • Parameter-Expansion passiert auch ohne Doppelpunkt; ich frage mich, warum man überhaupt einen Null-Befehl braucht
    • Die Parameter-Expansion findet zwar statt, aber ohne eine Konstruktion wie den Null-Befehl, die das Ergebnis konsumiert, behandelt die Shell den expandierten String als auszuführenden Befehl. Das habe ich auch in die FAQ aufgenommen
      % ${HELLO:=123}  
      zsh: command not found: 123  
      
      % : ${HELLO:=123}  
      % echo $HELLO  
      123  
      
    • Das Ergebnis des interpolierten Strings wird als auszuführender Befehl interpretiert
      #!/bin/sh  
      "${1:?missing argument, aborting!}"  
      
      $ sh foo.sh sh  
      sh-5.3$  
      
  • Wenn ich einen Befehl tippe und ihn später noch einmal ausführen möchte, setze ich am Zeilenanfang einen Doppelpunkt, damit er in der History gespeichert wird. Später kann ich die Zeile in der History finden und nur das erste Zeichen löschen, um sie tatsächlich auszuführen
    Daran, das für Nebeneffekte zu nutzen, die bei der Auswertung von Argumenten entstehen, hatte ich allerdings nicht gedacht
    • Statt : kann man auch # voranstellen und es als Kommentar speichern. Wenn es etwas ist, das man später ausführen will, hat das den Vorteil, dass Ausdrücke darin nicht vorab ausgewertet werden
    • In zsh kann man mit Meta-q oder Alt-q die aktuelle Zeile vorübergehend beiseiteschieben, einen anderen Befehl ausführen und sie danach wieder in den Befehlszeilenpuffer zurückholen
      https://nathangrigg.com/2014/04/zsh-push-line-or-edit/
  • Unter macOS verwende ich noch Bash 3, und dabei tritt folgender Fehler auf
    -bash: !}": event not found
    • Ich frage mich, ob es funktioniert, wenn man "!" weglässt
  • Der folgende Code aus Con-colon-sion dürfte Menschen eher verwirren als while true; do...
    while : colons are more than punctuation; do  
      echo "I love colons"  
      sleep 1  
    done  
    
    while true; do ist nur drei Zeichen länger als while :; do, also kurz genug, und der Code wirkt nicht wie ein Beispiel, das gut zu dem Punkt passt, den der Autor vermitteln will
    • Das ist kein Beispiel, das man wörtlich übernehmen soll, sondern ein Wortspiel. Wer diesen Code verstehen kann, kennt den Null-Befehl bereits, und der Doppelpunkt ist tatsächlich mehr als nur Satzzeichen
    • Eigentlich sollte wohl die folgende Endlosschleife gezeigt werden, aber beim Versuch, es elegant auszudrücken, ist der eigentliche Punkt verloren gegangen
      while :; do  
          something  
      done