1 points par GN⁺ 2 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Dans le shell, : est une commande nulle (null command) qui n’exécute aucune action et se contente d’évaluer ses arguments ; combinée à l’expansion de paramètres, elle permet de gérer de façon concise la vérification des arguments obligatoires et la définition de valeurs par défaut
  • : "${1:?missing argument, aborting!}" affiche un message de diagnostic sur stderr et se termine avec un état non nul si $1 est absent ou vide
  • En passant ${VAR:=default} comme argument à :, l’expansion est bien exécutée mais la chaîne résultante est jetée, ce qui permet de définir seulement la valeur par défaut sans exécuter le résultat de l’expansion comme commande
  • : peut aussi servir à vider un fichier via une redirection et à vérifier son accessibilité, comme commande vide pour trap, pour vérifier des variables dans un environnement set -u, ou encore dans une branche conditionnelle vide
  • : "${VAR:=default}" n’écrit le nom de la variable qu’une seule fois, ce qui réduit le risque de faute de frappe, et dans while : cela devient une condition toujours vraie, pratique pour exprimer une boucle infinie

Commande nulle et expansion de paramètres

  • : est une commande interne de commande nulle qui évalue ses arguments puis jette le résultat
    • Son origine remonte jusqu’au Thompson shell de 1971, où il servait aussi de label et de premier marqueur de commentaire d’Unix
  • Au lieu d’un bloc conditionnel de quatre lignes, on peut vérifier un argument obligatoire avec cette seule ligne
: "${1:?missing argument, aborting!}"
echo "Hello $1!"
  • La syntaxe d’expansion de paramètres ${name:?diagnostic} vérifie si $name n’est pas défini ou est vide
    • S’il n’y a pas de valeur, diagnostic est affiché sur stderr et le shell se termine avec un état non nul
    • S’il y a une valeur, le résultat est le même que $name
  • Sans commande nulle, exécuter seulement ${HELLO:=123} traite le résultat de l’expansion, 123, comme une commande et provoque command not found
    • : ${HELLO:=123} évalue l’expansion, définit HELLO=123, puis jette le résultat
  • : "${DATA_DIR:=/var/data}", contrairement à DATA_DIR="${DATA_DIR:-/var/data}", n’écrit le nom de la variable qu’une seule fois, ce qui réduit le risque de faute de frappe comme DATA_DRI

Comment utiliser :

  • Définir des valeurs par défaut

    • Définit la valeur par défaut d’une variable en jetant le résultat de l’expansion au lieu de l’exécuter
: "${DATA_DIR:=/var/data}"
: "${RETRIES:=3}"
  • Vider un fichier et vérifier l’accès

    • Combiné à une redirection, : permet de vider un ou plusieurs fichiers
: > error.log
: > error.log > access.log
  • On peut aussi vérifier si un fichier est lisible ou inscriptible à l’aide d’un sous-shell et d’une redirection
( : < dataset.json ) && echo YES
( : >> result.json ) && echo YES
  • Là où une commande vide est nécessaire

    • Utile quand la syntaxe exige une commande mais qu’aucune action réelle ne doit être effectuée, comme avec trap
trap : INT
sleep 60
  • On peut aussi le placer dans une branche conditionnelle laissée vide
if some-command; then
    :
else
    echo "command failed"
fi
  • Vérifier plusieurs variables

    • Avec set -u activé, on peut vérifier en une fois que plusieurs variables sont bien définies
set -u
: "$DEPLOY_ENV" "$HOST"
  • Boucle infinie

    • Comme : réussit toujours, on peut écrire une boucle infinie de manière concise
while :; do
  echo "I love colons"
  sleep 1
done

1 commentaires

 
GN⁺ 2 시간 전
Avis sur Lobste.rs
  • Si on construit l’invite comme ceci, même en copiant-collant toute la ligne, la partie invite est ignorée et seule la commande est exécutée
    : hayalci@tassadar ~/src/dool ; jj rebase -s dxw -d mrn
    • Inspiré de Plan 9, j’utilise aussi l’option autocd du shell et le format suivant
      ~/directoryname; <command>
      À chaque copie de la ligne de commande du shell, cela refait un cd vers le répertoire où la commande avait été exécutée à l’origine
    • Dans zsh, je configure le collage d’une espace insécable invisible et sans retour à la ligne pour effacer ce qui se trouve à gauche
      nbsp=$'\u00A0'  
      PS1="...$nbsp"  
      bindkey -s $nbsp '^u'  
      
  • J’utilise souvent le deux-points dans les Makefile pour un affichage plus propre
    out/%.o: src/%.c  
        @echo CC $@  
        @$(CC) -c -o $@ $<  
    
    Avec cette méthode, make peut lancer plusieurs processus echo en parallèle, qui écrivent sur le même flux et peuvent se gêner mutuellement. En le remplaçant par ceci, c’est le processus make lui-même qui écrit plutôt qu’un processus enfant
    out/%.o: src/%.c  
        : CC $@  
        @$(CC) -c -o $@ $<  
    
  • J’avais déjà vu cette technique dans des scripts shell, mais il était difficile de trouver une documentation utile avec man : ou whatis :
    C’est similaire à la commande true, sauf qu’elle ne réagit pas spécialement à --help, --version, etc., et qu’elle prend moins de caractères
    • Pour les commandes internes de Bash, il faut utiliser help plutôt que man
      $ help :  
      :: :  
          Null command.
      
          No effect; the command does nothing.
      
          Exit Status:  
          Always succeeds.  
      
    • Dans Fish, : est littéralement un alias de true
  • L’expansion des paramètres a lieu même sans deux-points, alors pourquoi avoir besoin d’une commande nulle ?
    • L’expansion des paramètres a bien lieu, mais sans syntaxe qui consomme le résultat comme une commande nulle, le shell traite la chaîne développée comme une commande à exécuter. Ce point a aussi été ajouté à la FAQ
      % ${HELLO:=123}  
      zsh: command not found: 123  
      
      % : ${HELLO:=123}  
      % echo $HELLO  
      123  
      
    • Le résultat de la chaîne interpolée est interprété comme la commande à exécuter
      #!/bin/sh  
      "${1:?missing argument, aborting!}"  
      
      $ sh foo.sh sh  
      sh-5.3$  
      
  • Quand je saisis une commande que je veux réexécuter plus tard, je mets un deux-points au début de la ligne pour l’enregistrer dans l’historique. Ensuite, je retrouve cette ligne dans l’historique, j’efface juste le premier caractère, et je peux vraiment l’exécuter
    En revanche, je n’avais pas pensé à l’utiliser pour les effets de bord produits lors de l’évaluation des arguments
    • On peut aussi mettre # au lieu de : pour l’enregistrer comme commentaire. Si c’est du contenu à exécuter plus tard, l’avantage est que les expressions qu’il contient ne seront pas évaluées à l’avance
    • Dans zsh, Meta-q ou Alt-q permet de mettre temporairement de côté la ligne en cours, d’exécuter une autre commande, puis de restaurer la ligne d’origine dans le buffer de ligne de commande une fois terminé
      https://nathangrigg.com/2014/04/zsh-push-line-or-edit/
  • Sur macOS, j’utilise encore Bash 3, et j’obtiens l’erreur suivante
    -bash: !}": event not found
    • Je me demande si cela fonctionne en supprimant l’usage de "!"
  • Le code suivant dans Con-colon-sion risque davantage de semer la confusion que while true; do...
    while : colons are more than punctuation; do  
      echo "I love colons"  
      sleep 1  
    done  
    
    while true; do ne fait que trois caractères de plus que while :; do, donc c’est déjà assez court, et ce code ne semble pas être un bon exemple du point que l’auteur veut faire passer
    • Ce n’est pas un exemple à suivre tel quel, mais un jeu de mots. Si on comprend ce code, c’est qu’on connaît la commande nulle, et le deux-points a effectivement plus qu’un simple rôle de ponctuation
    • Ce qu’il voulait montrer à l’origine, c’était plutôt une boucle infinie comme celle-ci, mais à force de vouloir faire stylé, il semble avoir perdu de vue l’essentiel
      while :; do  
          something  
      done