A quoi sert le colon intégré?

45

J'ai piraté beaucoup de scripts shell, et parfois les choses les plus simples me déconcertent. Aujourd'hui, j'ai rencontré un script qui faisait un usage intensif de la commande :intégrée de bash (deux points).

La documentation semble assez simple:

: (a colon)  
     : [arguments]  

Ne rien faire à part développer des arguments et effectuer des redirections. Le statut de retour est zéro.

Cependant, je n’avais auparavant vu cela que dans des démonstrations d’extension de coque. Le cas d'utilisation du script que j'ai rencontré utilisait beaucoup cette structure:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

Il y avait en fait des centaines de greps, mais ils sont plus ou moins identiques. Aucune redirection d'entrée / sortie n'est présente à part la structure simple ci-dessus. Aucune valeur de retour n'est vérifiée plus tard dans le script.

Je lis ceci comme une construction inutile qui dit "ou ne fait rien". A quoi bon mettre fin à ces greps avec "ou ne rien faire"? Dans quel cas cette construction entraînerait-elle un résultat différent de celui de simplement laisser tomber || :toutes les instances?

Caleb
la source
10
Un objectif possible que je peux voir est d’utiliser :une alternative à true. Peut errexit- être est-il défini et l'auteur se fiche du statut de sortie de certaines commandes.
jw013
la page liée Stackoverflow est un peu plus complète à l’OMI (il est donc bon de lire à la fois cette page et la page liée).
Trevor Boyd Smith le

Réponses:

29

Il semble que les :s de votre script soient utilisés à la place de true. S'il grepne trouve pas de correspondance dans le fichier, un code de sortie différent de zéro sera renvoyé. Comme jw013 le mentionne dans un commentaire, s'il errexitest défini, probablement par -esur la ligne shebang, le script se terminera si l'un des greps ne réussit pas à trouver une correspondance. Clairement, ce n’est pas ce que l’auteur voulait, c’est pourquoi il a ajouté || :pour que le statut de sortie de cette commande composée soit toujours égal à zéro, comme le plus courant (selon mon expérience) || true/ || /bin/true.

Kevin
la source
Duh. C'était dans le concept d'un script de construction RPM, et bien que je ne voie pas de code de sortie vérifier dans le script, j'ai oublié de considérer que le processus parent était peut-être en train de regarder.
Caleb
8
Si c'est le cas, j'appellerais cela une mauvaise pratique de script. C'est fonctionnellement équivalent à utiliser à la trueplace, mais l'intention sémantique est beaucoup plus claire avec true. :est plus approprié lorsqu'un NOP explicite est souhaité.
jw013
D'après mon expérience, il s'agit d'une pratique courante dans les scripts RPM. Cela ne devrait probablement pas être, mais nous y sommes.
mattdm
certains puristes préfèrent :au lieu de trueparce qu’il :est bashintégré à trueun système binaire compilé avec plus de surcharge. généralement, je l'utilise trueparce que le code est plus lisible (de même, je préfère utiliser à la sourceplace de .).
Trevor Boyd Smith le
36

La fonction :intégrée est également utile avec l’extension de shell «attribuer des valeurs par défaut» de Bash, où l’expansion est souvent utilisée uniquement pour l’effet secondaire et où la valeur développée est supprimée:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
Joni
la source
2
Je suis arrivé ici à la recherche de cela, j'ai été dérouté quand j'ai vu ce modèle dans un script pour déclarer les valeurs par défaut.
ffledgling
21

Je peux penser à deux endroits que j'ai utilisés :dans le passé.

while :
do
     shell commands
     some exit condition
done

C'est une boucle pour toujours.

function doSomethingStub {
    :
}

Mettez une fonction stub, juste pour obtenir un flux de contrôle de niveau supérieur correct.

Une utilisation que j’ai vue à l’époque: au lieu d’une ligne #!/bin/sh(ou autre), vous verriez une :ligne. Certains noyaux Real Unix ou shells Unix plus anciens utilisent ce terme pour signifier "Je suis un script shell, je l'ai exécuté". Si je me souviens bien, csh venait juste de faire son apparition en tant que shell interactif commun.

Bruce Ediger
la source
@BruceEdiger: Avez-vous une référence à la ligne "shecolon"?
l0b0
7
Enfin trouvé une référence et une explication ": au début d'un script": faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger
1
le comportement au début avec :est très étrange. J'ai constaté que le script s'exécute bien avec sh. où, comme lorsque vous démarrez le script sans shebang ..., il essaie de l'exécuter avec n'importe quel shell en cours d'exécution (ainsi, si vous l'exécutez, essayez bashde l'exécuter comme bashsi vous l'aviez cshensuite, il essayait de l'exécuter en tant que csh).
Trevor Boyd Smith le
19

L' :intégré était déjà dans le shell Thompson - il est documenté pour Unix V6 en 1975. Dans le shell Thompson, :indique une étiquette pour la gotocommande. Si vous n'avez jamais essayé d'appeler gotosur une ligne commençant par , cette ligne était en réalité un commentaire.

Le shell Bourne , ancêtre des shell Bourne / POSIX tels que nous les connaissons, n’a jamais eu de gotoréponse connue, mais conservé :comme commande no-op (il était déjà présent dans Unix V7 ).

Gilles, arrête de faire le mal
la source
Point pour le contexte historique informatif.
Tony Barganski
12

J'ai extrait une ancienne référence: "L'environnement de programmation UNIX" (c) 1984 de Kernighan et Pike.

Page 147 (Programmation Shell) dit ceci:

":" est une commande intégrée du shell qui ne fait qu'évaluer ses arguments et renvoyer "true". Au lieu de cela [référence à un exemple de script], nous aurions pu utiliser true , qui renvoie simplement un statut de sortie vrai. (Il existe également une commande false .) Mais ':' est plus efficace que true car il n'exécute pas de commande à partir du système de fichiers . [Les italiques / l'emphase est à moi.]

fracjackmac
la source
2
Bien sûr, truec’est désormais un shell intégré à de nombreux systèmes.
tripleee
8

Je semble me souvenir que les premières versions du shell n’avaient pas de syntaxe de commentaire. Une ligne commençant par :(qui aurait probablement été un exécutable réel, similaire à /bin/true) aurait été la meilleure alternative.

Voici une page de manuel relative à l’ancienne coquille Thompson (aucune relation); il n'y a aucune mention de syntaxe de commentaire.

Keith Thompson
la source
4
L'origine de :était en fait un indicateur d'étiquette pour la gotocommande, dans un ancien shell (je ne sais pas lequel). Une étiquette : somethingpourrait en effet être utilisée comme commentaire s’il n’y avait pas de correspondance goto. La pratique a collé même après avoir gotodisparu.
Gilles, arrête de faire le mal
8

":" est pratique pour le débogage.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Si vous exécutez normalement la fonction de débogage n’est jamais exécutée, sh doit simplement passer au-dessus du noop (les variables et les caractères génériques sont développés). Si un débogage plus approfondi est requis, supprimez le noop de la variable et la fonction debug est appelée avec tous les arguments requis.

Une autre utilisation pratique est celle de commentaire de bloc, élément manquant dans la syntaxe du shell.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
Colin
la source