Quelle est l'utilité de la commande: dans les scripts shell, étant donné qu'elle ne fait explicitement rien?

27

Dans la réponse à cette question sur les commentaires dans les scripts shell , il est indiqué qu'il :s'agit d'une commande null qui ne fait rien explicitement (mais ne doit pas être utilisée pour les commentaires).

Quelle serait l'utilité d'une commande qui ne fait absolument rien?

DQdlM
la source
1
Voir aussi À quoi sert le côlon intégré .
jw013
2
Voir également cette question qui a une réponse encore meilleure ici , à savoir qui :doit être intégrée, tandis que ce truen'est pas le cas, ce qui affecte la portée des variables
Old Pro
2
Il ne fait explicitement rien gracieusement .
mikeserv

Réponses:

19

J'utilise généralement trueen boucles; Je pense que c'est plus clair:

while true; do
    ...
done

Le seul endroit que j'ai trouvé :très utile est dans les déclarations de cas, si vous devez faire correspondre quelque chose mais que vous ne voulez rien faire. Par exemple:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac
Scientifique fou
la source
3
Je suis d'accord. truepour une condition, :pour un NOP.
jw013
1
bash accepte case a in a ) ;; esac. Y a-t-il des obus qui n'acceptent pas cela?
Kaz
@Kaz: Selon la grammaire du shell POSIX , case ${var} in value);; *) do_something;; esacest acceptable. La :commande n'est pas nécessaire pour les cas vides.
Richard Hansen
12

À l'origine, il a été utilisé pour déterminer qu'il s'agissait d'un programme shell Bourne, par opposition à un programme compilé en C. C'était avant shebang et plusieurs langages de script (csh, perl). Vous pouvez toujours exécuter un script commençant par ::

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

Il exécutera généralement le script contre $SHELL(ou /bin/sh).

Depuis lors, l'utilisation principale est d'évaluer les arguments. J'utilise toujours:

: ${EDITOR:=vim}

pour définir une valeur par défaut dans un script.

Arcege
la source
11

: est utile pour écrire des boucles qui doivent être terminées de l'intérieur.

while :
do
    ...stuff...
done

Cela s'exécutera indéfiniment, sauf si breakou exitest appelé, ou le shell reçoit un signal de terminaison.

Kyle Jones
la source
3
Je pense que cela while true; do ...; donecommunique mieux les intentions au lecteur quewhile :; do ...; done
Richard Hansen
9

Lorsque vous voulez une instruction «à moins» dans les scripts shell, vous utilisez soit une condition «non», qui peut sembler loufoque pour certains des tests, soit vous utilisez «:» dans la clause true, avec du code réel dans la false- clause.

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

La "condition exotique" pourrait être quelque chose que vous ne voulez pas nier, ou c'est beaucoup plus clair si vous n'utilisez pas la "logique négative".

Bruce Ediger
la source
1
Il apparaît également dans les scripts générés par autoconfcar il est beaucoup plus facile d'ajouter une valeur :par défaut pour les branches vides que de comprendre comment inverser la condition.
Dietrich Epp
2
Je ne vois pas comment s'en tenir à un !devant [ some-exotic-condition ]est maladroit, mais un superflu : elseaprès ce n'est pas maladroit.
Kaz
@Kaz a un bon point. Gardons à l'esprit que créer des conditions exotiques est au mieux difficile. Si vous devez tout nier, c'est une chose, mais cela pourrait simplement rendre la condition moins claire. Fait un '!' nier toute la condition, ou juste le premier terme? Mieux vaut parfois avoir une vraie clause ':'.
Bruce Ediger
Le !jeton annule tout un élément de canal de commande. while ! grep ... ; do ... done ou if ! [ ... ] ; then ... fi. C'est essentiellement externe à la test/[]syntaxe. Voir: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Kaz
5

Je n'ai jamais utilisé cela en plus du caractère # pour commenter temporairement une ligne, dans une situation où le commentaire de la ligne produit une erreur de syntaxe, en raison d'un défaut dans la grammaire du shell de ne pas autoriser une séquence vide de commandes :

if condition ; then
    :# temporarily commented out command
fi

Sans: nous avons une séquence de commandes manquante, ce qui est une erreur de syntaxe.

Kaz
la source
4

Il y a deux cas où je trouve :utile:

Affectations de variables par défaut

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

Il s'agit d'un moyen pratique pour permettre aux utilisateurs de votre script shell de remplacer un paramètre sans modifier le script. (Cependant, les arguments de ligne de commande sont meilleurs car vous ne courez pas le risque d'un comportement inattendu si l'utilisateur possède par hasard la variable que vous utilisez dans son environnement exporté.) Voici comment l'utilisateur remplacerait le paramètre:

VAR="other value" ./script

La ${VAR=value}syntaxe dit ensemble VARà valuesi VARce n'est déjà, puis développez à la valeur de la variable. Comme nous ne nous soucions pas encore de la valeur de la variable, elle est passée en argument à la commande no-op :pour la jeter.

Même s'il :s'agit d'une commande no-op, l'expansion est effectuée par le shell (pas la :commande!) Avant d'exécuter la :commande afin que l'affectation des variables se produise toujours (le cas échéant).

Il serait également acceptable d'utiliser trueou une autre commande à la place :, mais le code devient plus difficile à lire car l'intention est moins claire.

Le script suivant fonctionnerait également:

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

Mais ce qui précède est beaucoup plus difficile à maintenir. Si une ligne utilisant ${VAR}est ajoutée au-dessus de cette printfligne, l'extension d'affectation par défaut doit être déplacée. Si le développeur oublie de déplacer cette affectation, un bogue est introduit.

Quelque chose à mettre dans un bloc conditionnel vide

Les blocs conditionnels vides doivent généralement être évités, mais ils sont parfois utiles:

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

Certaines personnes soutiennent que le fait d'avoir un vrai ifbloc vide peut rendre le code plus facile à lire que la négation du test. Par exemple:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

est sans doute plus facile à lire que:

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

Cependant, je pense qu'il existe quelques approches alternatives qui sont meilleures qu'un vrai bloc vide:

  1. Mettez la condition dans une fonction:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
  2. Mettez la condition entre accolades (ou entre parenthèses, mais les parenthèses génèrent un processus de sous-shell et toutes les modifications apportées à l'environnement à l'intérieur du sous-shell ne seront pas visibles en dehors du sous-shell) avant de nier:

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
  3. Utilisez ||au lieu de if:

    [ -f foo ] && bar || baz || {
        do_something_here
    }

    Je préfère cette approche lorsque la réaction est une simple ligne, telle que l'affirmation de conditions:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"
Richard Hansen
la source
1

Dans l'ancien shell pré-bourne dans les anciennes versions d'UNIX, la :commande était à l'origine destinée à spécifier les étiquettes pour goto(c'était une commande distincte qui enroule l'entrée à l'endroit où se trouve l'étiquette, donc les étiquettes ne pouvaient pas être une syntaxe distincte que le shell est au courant. ifétait également une commande distincte.) Elle est rapidement devenue utilisée pour les commentaires, avant qu'il y ait une syntaxe de commentaire (a #été utilisée pour le retour arrière) et ces jours-ci sont autant de compatibilité que tout.

Aléatoire832
la source
0

En plus de l'utiliser comme une instruction qui ne fait rien, vous pouvez l'utiliser pour commenter des instructions individuelles en les transformant en arguments pour:.

Martin Stein
la source
Ce ne sera pas exactement un commentaire car : echo write this line > myfileil créera toujours un fichier vide.
Arcege
5
Comme expliqué dans le lien dans la question, ce :n'est PAS un mécanisme de commentaires adéquat.
jw013