web-dev-qa-db-fra.com

Quel est le cas d'utilisation de noop [:] dans bash?

J'ai cherché noop in bash (:), mais je n'ai pas pu trouver de bonne information. Quel est le but exact ou le cas d'utilisation de cet opérateur?

J'ai essayé de suivre et ça marche comme ça pour moi:

[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30

S'il vous plaît laissez-moi savoir, tout cas d'utilisation de cet opérateur en temps réel ou tout endroit où il est obligatoire de l'utiliser.

103
Mandar Pande

C'est là plus pour des raisons historiques. Le côlon construit : est exactement équivalent à true. Il est de tradition d'utiliser true lorsque la valeur de retour est importante, par exemple dans une boucle infinie:

while true; do
  echo 'Going on forever'
done

C'est traditionnel d'utiliser : lorsque la syntaxe du shell nécessite une commande mais que vous n’avez rien à faire.

while keep_waiting; do
  : # busy-wait
done

Le : construit date depuis le Thompson Shell , il était présent dans nix v6 . : était un indicateur d'étiquette pour l'instruction goto de Shell Shell. L'étiquette peut être n'importe quel texte, donc : doublé en tant qu'indicateur de commentaire (s'il n'y a pas de goto comment, puis : comment est effectivement un commentaire). Le Bourne Shell n'avait pas goto mais conservait :.

Un langage commun qui utilise : est : ${var=VALUE} , qui définit var sur VALUE s'il n'a pas été défini et ne fait rien si var était déjà défini. Cette construction n'existe que sous la forme d'une substitution de variable, et cette substitution de variable doit faire partie d'une commande: une commande no-op sert parfaitement.

Voir aussi À quoi sert le colon intégré? .

150
Gilles

Je l'utilise pour les déclarations if lorsque je commente tout le code. Par exemple, vous avez un test:

if [ "$foo" != "1" ]
then
    echo Success
fi

mais vous voulez commenter temporairement tout ce qui est contenu dans:

if [ "$foo" != "1" ]
then
    #echo Success
fi

Ce qui fait que bash génère une erreur de syntaxe:

line 4: syntax error near unexpected token `fi'
line 4: `fi'

Bash ne peut pas avoir de blocs vides (WTF). Donc, vous ajoutez un no-op:

if [ "$foo" != "1" ]
then
    #echo Success
    :
fi

ou vous pouvez utiliser le no-op pour commenter les lignes:

if [ "$foo" != "1" ]
then
    : echo Success
fi
14
Stephen Ostermiller

Vous utiliseriez : pour fournir une commande qui réussit mais ne fait rien. Dans cet exemple, la commande "verbosity" est désactivée par défaut en la configurant sur :. L'option 'v' l'active.

#!/bin/sh
# example
verbosity=:                         
while getopts v OPT ; do          
   case $OPT in                  
       v)        
           verbosity=/bin/realpath 
       ;;
       *)
           exit "Cancelled"
       ;;             
   esac                          
done                              

# `$verbosity` always succeeds by default, but does nothing.                              
for i in * ; do                   
  echo $i $($verbosity $i)         
done                              

$ example
   file

$ example -v
   file /home/me/file  
7
Mark

Si tu utilises set- e puis || : est un excellent moyen de ne pas quitter le script si un échec survient (il le fait explicitement passer).

7
Crisfole

Ignorer les arguments alias

Parfois, vous voulez avoir un alias qui ne prend aucun argument. Vous pouvez le faire en utilisant ::

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there
5
Ulysse BN

Une utilisation est comme commentaires multilignes, ou pour commenter une partie de votre code à des fins de test en l’utilisant avec un fichier here.

: << 'EOF'

This part of the script is a commented out

EOF

N'oubliez pas d'utiliser des guillemets autour de EOF pour que tout code contenu à l'intérieur ne soit pas évalué, comme $(foo). Il pourrait également valoir la peine d’utiliser un nom de terminateur intuitif, tel que NOTES, SCRATCHPAD ou TODO.

4
Geoffrey Ritchey

Deux des miens.

Intégrer les commentaires du POD

Une application assez funky de : est pour incorporant des commentaires POD dans des scripts bash , afin que les pages de manuel puissent être générées rapidement. Bien sûr, on finirait par réécrire le script entier en Perl ;-)

Liaison de fonction d'exécution

C'est une sorte de modèle de code pour les fonctions de liaison au moment de l'exécution. F.i., avez une fonction de débogage pour faire quelque chose que si un certain drapeau est défini:

#!/bin/bash
# noop-demo.sh 
shopt -s expand_aliases

dbg=${DBG:-''}

function _log_dbg {
    echo >&2 "[DBG] $@"
}

log_dbg_hook=':'

[ "$dbg" ] && log_dbg_hook='_log_dbg'

alias log_dbg=$log_dbg_hook


echo "Testing noop alias..."
log_dbg 'foo' 'bar'

Vous recevez:

$ ./noop-demo.sh 
Testing noop alias...
$ DBG=1 ./noop-demo.sh 
Testing noop alias...
[DBG] foo bar
3
sphakka

Parfois, les clauses no-op peuvent rendre votre code plus lisible.

Cela peut être une question d'opinion, mais voici un exemple. Supposons que vous ayez créé une fonction qui fonctionne en prenant deux chemins unix. Il calcule le "chemin de changement" nécessaire pour passer d'un chemin à un autre. Vous placez une restriction sur votre fonction selon laquelle les chemins doivent tous deux commencer par un '/' OR les deux ne doivent pas.

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        true      # continue with function
    else
        return 1  # Skip function.
    fi

Certains développeurs voudront supprimer le no-op mais cela signifierait la négation du conditionnel:

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
    then
        return 1  # Skip function.
    fi

À présent, à mon avis, les clauses dans lesquelles vous ne souhaitez pas exécuter la fonction ne sont pas claires. Pour éliminer le no-op et le faire clairement, vous voudriez déplacer la clause if hors de la fonction:

    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        cdPath=$(chgPath pathA pathB)   # (we moved the conditional outside)

Cela a l'air mieux, mais souvent nous ne pouvons pas faire cela. nous voulons que le contrôle soit effectué dans la fonction.

Alors, combien de fois cela arrive-t-il? Pas très souvent. Peut-être une ou deux fois par an. Il arrive assez souvent que vous deviez en être conscient. Je n'hésite pas à l'utiliser quand je pense que cela améliore la lisibilité de mon code (quelle que soit la langue).

2
Bitdiot

Un peu lié à cette réponse , je trouve ce no-op plutôt pratique à pirater polyglotte scripts. Par exemple, voici un commentaire valide pour bash et pour vimscript:

":" #    this is a comment
":" #    in bash, ‘:’ is a no-op and ‘#’ starts a comment line
":" #    in vimscript, ‘"’ starts a comment line

Bien sûr, nous avons peut-être utilisé true aussi bien, mais : étant un signe de ponctuation et non un mot anglais non pertinent, il est clair qu’il s’agit d’un jeton de syntaxe.


Quant à pourquoi quelqu'un ferait une chose aussi délicate que d'écrire un script polyglotte (en plus d'être cool): cela s'avère utile dans les situations où nous écrivions normalement plusieurs fichiers de script dans plusieurs langues différentes, avec fichier X faisant référence au fichier Y.

Dans une telle situation, la combinaison des deux scripts dans un seul fichier polyglotte évite tout travail dans X pour déterminer le chemin d'accès à Y (il s'agit simplement de "$0"). Plus important encore, cela facilite le déplacement ou la distribution du programme.

  • Un exemple commun. Il y a un problème connu de longue date avec shebangs: la plupart des systèmes (y compris Linux et Cygwin) n'autorisent que un argument à transmettre à l'interprète. Le Shebang suivant:

    #!/usr/bin/env interpreter --load-libA --load-libB
    

    déclenchera la commande suivante:

    /usr/bin/env "interpreter --load-libA --load-libB" "/path/to/script"
    

    et non l'intention:

    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    Ainsi, vous finirez par écrire un script wrapper, tel que:

    #!/usr/bin/env sh
    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    C'est là que la polyglossie entre en scène.

  • Un exemple plus spécifique. J'ai écrit un jour un script bash qui, entre autres choses, appelait Vim. J'avais besoin de donner à Vim une configuration supplémentaire, ce qui pourrait être fait avec l'option --cmd "arbitrary vimscript command here". Cependant, cette configuration était importante, de sorte que l'inclure dans une chaîne aurait été terrible (si jamais possible). Par conséquent, une meilleure solution consistait à l'écrire in extenso dans un fichier de configuration, puis à faire lire ce fichier à Vim avec -S "/path/to/file". Je me suis donc retrouvé avec un fichier polyglot bash/vimscript.

2
Maëlan

supposons que vous ayez une commande que vous souhaitez enchaîner pour le succès d'une autre:

cmd="some command..."
$cmd
[ $? -eq 0 ] && some-other-command

mais maintenant vous voulez exécuter les commandes de manière conditionnelle et vous voulez montrer les commandes qui seraient exécutées (à sec):

cmd="some command..."
[ ! -z "$DEBUG" ] && echo $cmd
[ -z "$NOEXEC" ] && $cmd
[ $? -eq 0 ] && {
    cmd="some-other-command"
    [ ! -z "$DEBUG" ] && echo $cmd
    [ -z "$NOEXEC" ] && $cmd
}

donc, si vous définissez DEBUG et NOEXEC, la deuxième commande n'apparaît jamais. c'est parce que la première commande ne s'exécute jamais (parce que NOEXEC n'est pas vide) mais que l'évaluation de ce fait vous laisse un retour de 1, ce qui signifie que la commande subordonnée ne s'exécute jamais (mais vous voulez qu'elle s'exécute, car elle est sèche). donc pour résoudre ce problème, vous pouvez réinitialiser la valeur de sortie laissée sur la pile avec un noop:

[ -z "$NOEXEC" ] && $cmd || :
0
ekkis