Quel est le but d'une commande qui ne fait rien, étant un peu plus qu'un leader de commentaire, mais est en fait un shell intégré en soi?
C'est plus lent que l'insertion d'un commentaire dans vos scripts d'environ 40% par appel, ce qui varie probablement considérablement en fonction de la taille du commentaire. Les seules raisons possibles que je peux voir sont les suivantes:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true' (lazy programming)
while : ; do command ; done
Je suppose que ce que je recherche vraiment, c'est quelle application historique il aurait pu avoir.
Réponses:
Historiquement , les shells Bourne n'avaient pas
true
etfalse
comme intégré des commandes.true
était plutôt simplement aliasé:
, etfalse
quelque chose commelet 0
.:
est légèrement meilleur quetrue
pour la portabilité aux anciennes coquilles dérivées de Bourne. À titre d'exemple simple, envisagez de n'avoir ni l'!
opérateur de pipeline ni l'||
opérateur de liste (comme c'était le cas pour certains anciens obus Bourne). Cela laisse laelse
clause de l'if
instruction comme le seul moyen de branchement basé sur le statut de sortie:Étant donné que
if
requiert unethen
clause non vide et que les commentaires ne comptent pas comme non vides,:
sert de no-op.De nos jours (c'est-à-dire: dans un contexte moderne), vous pouvez généralement utiliser soit
:
outrue
. Les deux sont spécifiés par POSIX, et certains trouventtrue
plus faciles à lire. Cependant, il y a une différence intéressante: il:
s'agit d'un soi-disant POSIX spécial intégré , alors qu'iltrue
est un intégré standard .Des éléments intégrés spéciaux doivent être intégrés à la coque; Les fonctions intégrées régulières ne sont «généralement» intégrées, mais elles ne sont pas strictement garanties. Il ne devrait généralement pas y avoir de programme régulier nommé
:
avec la fonction detrue
dans PATH de la plupart des systèmes.La différence la plus cruciale est probablement qu'avec les modules intégrés spéciaux, toute variable définie par le module intégré - même dans l'environnement lors de l'évaluation d'une commande simple - persiste après la fin de la commande, comme illustré ici en utilisant ksh93:
Notez que Zsh ignore cette exigence, tout comme GNU Bash sauf lorsqu'il fonctionne en mode de compatibilité POSIX, mais tous les autres principaux shells "dérivés POSIX sh" observent cela, y compris dash, ksh93 et mksh.
Une autre différence est que les fonctions intégrées régulières doivent être compatibles avec
exec
- démontré ici en utilisant Bash:POSIX note également explicitement que cela
:
peut être plus rapide quetrue
, bien qu'il s'agisse bien sûr d'un détail spécifique à l'implémentation.la source
exec
?true
s'agit d'une intégration standard, mais il est incorrect en ce qu'ilexec
utilise à la/bin/true
place de l'intégration.: ${var?not initialized}
et al.:
c'est une fonction spéciale intégrée et ne devrait pas avoir de fonction nommée par elle. Mais l'exemple le plus courant de bombe à fourche ne:(){ :|: & };:
nomme-t-il pas une fonction avec un nom:
?Je l'utilise pour activer / désactiver facilement les commandes variables:
Donc
Cela en fait un script propre. Cela ne peut pas être fait avec '#'.
Aussi,
est l'un des moyens les plus simples de garantir que «afile» existe mais a une longueur nulle.
la source
>afile
est encore plus simple et obtient le même effet.vecho=":"
? Juste pour la lisibilité?Une application utile pour: est si vous souhaitez uniquement utiliser des extensions de paramètres pour leurs effets secondaires plutôt que de transmettre leur résultat à une commande. Dans ce cas, vous utilisez le PE comme argument pour: ou false selon que vous souhaitez un état de sortie de 0 ou 1. Un exemple peut être
: "${var:=$1}"
. Puisqu'il:
est intégré, il devrait être assez rapide.la source
: $((a += 1))
(++
et les--
opérateurs n'ont pas besoin d'être implémentés selon POSIX.). En bash, ksh et d'autres shells possibles, vous pouvez aussi faire:((a += 1))
ou((a++))
mais ce n'est pas spécifié par POSIX.(())
est spécifié comme une fonctionnalité facultative. "Si une séquence de caractères commençant par" (("serait analysée par le shell comme une expansion arithmétique si elle était précédée d'un '$', les shells qui implémentent une extension par laquelle" ((expression)) "est évalué comme une expression arithmétique peut traiter le "((" comme présentant comme une évaluation arithmétique au lieu d'une commande de regroupement. ":
peut également être pour le commentaire de bloc (similaire à / * * / en langage C). Par exemple, si vous souhaitez ignorer un bloc de code dans votre script, vous pouvez le faire:la source
\
échapper à l' un des caractères délimiteurs pour le même effet:: <<\SKIP
.Si vous souhaitez tronquer un fichier à zéro octet, utile pour effacer les journaux, essayez ceci:
la source
> file.log
est plus simple et obtient le même effet.:>
est plus portable. Certains shells (comme le mienzsh
) instancient automatiquement un chat dans le shell actuel et écoutent stdin lorsqu'ils reçoivent une redirection sans commande. Plutôt quecat /dev/null
,:
c'est beaucoup plus simple. Souvent, ce comportement est différent dans les shells interactifs plutôt que dans les scripts, mais si vous écrivez le script d'une manière qui fonctionne également de manière interactive, le débogage par copier-coller est beaucoup plus facile.: > file
diffère- t-iltrue > file
(à part le nombre de personnages et le visage heureux) dans une coque moderne (en supposant:
ettrue
tout aussi rapide)?C'est similaire à
pass
Python.Une utilisation serait de bloquer une fonction jusqu'à ce qu'elle soit écrite:
la source
Deux autres utilisations non mentionnées dans d'autres réponses:
Enregistrement
Prenez cet exemple de script:
La première ligne
set -x
,, fait que le shell imprime la commande avant de l'exécuter. C'est une construction assez utile. L'inconvénient est que leecho Log message
type habituel de déclaration imprime désormais le message deux fois. La méthode du côlon contourne cela. Notez que vous devrez toujours échapper les caractères spéciaux comme vous le feriez pourecho
.Titres de poste Cron
Je l'ai vu utilisé dans des tâches cron, comme ceci:
Il s'agit d'un travail cron qui exécute le script
/opt/backup.sh
tous les jours à 10h45. L'avantage de cette technique est qu'elle permet de mieux voir les sujets des e-mails lors de l'/opt/backup.sh
impression d'une sortie.la source
set -x
, les commandes imprimées (y compris quelque chose comme: foobar
) vont à stderr.Vous pouvez l'utiliser en conjonction avec backticks (
``
) pour exécuter une commande sans afficher sa sortie, comme ceci:Bien sûr, vous pouvez le faire
some_command > /dev/null
, mais la:
version-est un peu plus courte.Cela étant dit, je ne recommanderais pas de le faire, car cela ne ferait qu'embrouiller les gens. Cela m'est venu à l'esprit comme un cas d'utilisation possible.
la source
Il est également utile pour les programmes polyglottes:
Ceci est maintenant à la fois un script shell exécutable et un programme JavaScript: ce qui signifie
./filename.js
,sh filename.js
etnode filename.js
tout le travail.(Certainement un peu d'une utilisation étrange, mais néanmoins efficace.)
Quelques explications, comme demandé:
Les scripts shell sont évalués ligne par ligne; et la
exec
commande, lorsqu'elle est exécutée, termine le shell et remplace son processus par la commande résultante. Cela signifie que pour le shell, le programme ressemble à ceci:Tant qu'aucune expansion de paramètre ou alias ne se produit dans le mot, n'importe quel mot dans un script shell peut être entouré de guillemets sans changer sa 'signification; cela signifie que
':'
c'est équivalent à:
(nous l'avons seulement mis entre guillemets ici pour obtenir la sémantique JavaScript décrite ci-dessous)... et comme décrit ci-dessus, la première commande sur la première ligne est un no-op (cela se traduit par
: //
, ou si vous préférez citer les mots':' '//'
,. Notez que le//
ne porte aucune signification particulière ici, comme il le fait en JavaScript; c'est juste un mot vide de sens qui est jeté.)Enfin, la deuxième commande sur la première ligne (après le point-virgule), est la vraie viande du programme: c'est l'
exec
appel qui remplace le shell-script invoqué , avec un processus Node.js invoqué pour évaluer le reste du script.Pendant ce temps, la première ligne, en JavaScript, est analysée comme un littéral de chaîne (
':'
), puis un commentaire, qui est supprimé; ainsi, pour JavaScript, le programme ressemble à ceci:Puisque le littéral de chaîne est sur une ligne par lui-même, c'est une instruction no-op, et est donc supprimé du programme; cela signifie que la ligne entière est supprimée, ne laissant que votre code de programme (dans cet exemple, le
function(){ ... }
corps.)la source
: //;
et~function(){}
faire? Merci:)
~function(){}
, c'est un peu plus compliqué. Il y a quelques autres réponses ici qui touchent à cela, bien qu'aucune ne l'explique vraiment à ma satisfaction ... si aucune de ces questions ne l'explique assez bien pour vous, n'hésitez pas à la poster comme une question ici, je serai heureux de répondre en profondeur à une nouvelle question.node
. Donc, la partie fonction est entièrement javascript! Je suis d'accord avec un opérateur unaire devant l'IIFE. Je pensais que c'était trop bash en premier lieu et en fait, je n'ai pas vraiment compris le sens de votre message. Je vais bien maintenant, merci pour le temps que vous avez passé à ajouter «décomposition»!~{ No problem. (= }
Fonctions d'auto-documentation
Vous pouvez également utiliser
:
pour incorporer de la documentation dans une fonction.Supposons que vous ayez un script de bibliothèque
mylib.sh
, offrant une variété de fonctions. Vous pouvez soit source la bibliothèque (. mylib.sh
) et appeler les fonctions directement après cela (lib_function1 arg1 arg2
), soit éviter d'encombrer votre espace de noms et appeler la bibliothèque avec un argument de fonction (mylib.sh lib_function1 arg1 arg2
).Ne serait-ce pas bien si vous pouviez également taper
mylib.sh --help
et obtenir une liste des fonctions disponibles et leur utilisation, sans avoir à maintenir manuellement la liste des fonctions dans le texte d'aide?Quelques commentaires sur le code:
declare -f
pour énumérer toutes les fonctions disponibles, puis les filtre via sed pour n'afficher que les fonctions avec le préfixe approprié.mylib.sh function1
et il est traduit en internelib_function1
. C'est un exercice laissé au lecteur.$1
. En même temps, il encombrera votre espace de noms si vous sourcez la bibliothèque. Si vous n'aimez pas cela, vous pouvez soit changer le nom en quelque chose comme,lib_help
soit vérifier les arguments--help
dans le code principal et appeler manuellement la fonction d'aide.la source
J'ai vu cette utilisation dans un script et j'ai pensé que c'était un bon substitut pour invoquer un nom de base dans un script.
... ceci remplace le code:
basetool=$(basename $0)
la source
basetool=${0##*/}