¿Cuál es la utilidad del comando: en el script de shell, dado que explícitamente no hace nada?

27

En la respuesta a esta pregunta sobre los comentarios en las secuencias de comandos de shell , se indica que :es un comando nulo que explícitamente no hace nada (pero no debe usarse para comentarios).

¿Cuál sería la utilidad de un comando que no hace absolutamente nada?

DQdlM
fuente
1
Vea también ¿ Para qué sirve el colon incorporado ?
jw013
2
Vea también esta pregunta que tiene una respuesta aún mejor aquí , es decir, que :se requiere que sea incorporada, mientras trueque no lo es, lo que afecta el alcance de las variables
Old Pro
2
No hace nada explícitamente con gracia .
mikeserv

Respuestas:

19

Normalmente lo uso trueen bucles; Creo que está más claro:

while true; do
    ...
done

El único lugar que he encontrado que :es realmente útil es en las declaraciones de casos, si necesita hacer coincidir algo pero no quiere hacer nada. Por ejemplo:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac
Científico loco
fuente
3
Estoy de acuerdo. truepor una condición, :por un NOP.
jw013
1
bash acepta case a in a ) ;; esac. ¿Hay algunas conchas que no aceptan esto?
Kaz
@Kaz: Según la gramática de shell POSIX , case ${var} in value);; *) do_something;; esaces aceptable. El :comando no es necesario para casos vacíos.
Richard Hansen
12

Originalmente, se usaba para determinar que era un programa de shell Bourne, a diferencia del programa compilado en C. Esto fue antes de shebang y múltiples lenguajes de script (csh, perl). Todavía puede ejecutar un script que comience simplemente con ::

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

Generalmente ejecutará el script contra $SHELL(o /bin/sh).

Desde entonces, el uso principal es evaluar los argumentos. Sigo usando:

: ${EDITOR:=vim}

para establecer un valor predeterminado en un script.

Arcege
fuente
11

: es útil para escribir bucles que deben terminarse desde dentro.

while :
do
    ...stuff...
done

Esto se ejecutará para siempre a menos que breako exitse llame, o el shell reciba una señal de terminación.

Kyle Jones
fuente
3
Siento que eso while true; do ...; donecomunica intenciones al lector mejor quewhile :; do ...; done
Richard Hansen
9

Cuando desee una declaración "a menos que" en el script de shell, use una condición "no", que puede parecer tonta para algunas de las pruebas, o use ':' en la cláusula verdadera, con código real en el falso- cláusula.

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

La "condición exótica" podría ser algo que no desea negar, o eso es mucho más claro si no utiliza la "lógica negativa".

Bruce Ediger
fuente
1
También aparece en scripts generados por autoconfporque es mucho más fácil agregar un valor predeterminado :para ramas vacías que averiguar cómo revertir la condición.
Dietrich Epp
2
No puedo ver cómo pegarse en un !frente [ some-exotic-condition ]es tonto, pero un superfluo : elsedespués de que no es tonto.
Kaz
@Kaz tiene un buen punto. Tengamos en cuenta que encontrar condiciones exóticas es difícil en el mejor de los casos. Si tiene que negarlo todo, eso es una cosa, pero podría hacer que la condición sea menos clara. ¿Hace un '!' ¿negar toda la condición o solo el primer término? Es mejor tener una cláusula verdadera ':' a veces.
Bruce Ediger
El !token niega un elemento de tubería de comando completo. while ! grep ... ; do ... done o if ! [ ... ] ; then ... fi. Es básicamente externo a la test/[]sintaxis. Ver: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Kaz
5

Solo he usado esto además del carácter # para comentar temporalmente una línea, en una situación en la que comentar la línea produce un error de sintaxis, debido a un defecto en la gramática del shell de no permitir una secuencia vacía de comandos :

if condition ; then
    :# temporarily commented out command
fi

Sin el: nos falta una secuencia de comandos, que es un error de sintaxis.

Kaz
fuente
4

Hay dos casos en los que me parece :útil:

Asignaciones de variables predeterminadas

#!/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}"

Esta es una manera conveniente de permitir a los usuarios de su script de shell anular una configuración sin editar el script. (Sin embargo, los argumentos de la línea de comandos son mejores porque no corre el riesgo de un comportamiento inesperado si el usuario coincide con la variable que usa en su entorno exportado). Así es como el usuario anularía la configuración:

VAR="other value" ./script

La ${VAR=value}sintaxis dice establecer VARen valuesi aún VARno está establecida, luego expandir al valor de la variable. Como todavía no nos importa el valor de la variable, se pasa como un argumento al comando no-op :para descartarla.

Aunque :es un comando no :operativo, el shell realiza la expansión (¡no el comando!) Antes de ejecutar el :comando, por lo que la asignación de variables aún ocurre (si corresponde).

También sería aceptable usar trueo algún otro comando en lugar de :, pero el código se vuelve más difícil de leer porque la intención es menos clara.

El siguiente script también funcionaría:

#!/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}"

Pero lo anterior es mucho más difícil de mantener. Si ${VAR}se agrega una línea usando encima de esa printflínea, se debe mover la expansión de asignación predeterminada. Si el desarrollador olvida mover esa tarea, se introduce un error.

Algo para poner en un bloque condicional vacío

Los bloques condicionales vacíos generalmente deben evitarse, pero a veces son útiles:

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

Algunas personas argumentan que tener un ifbloque verdadero vacío puede hacer que el código sea más fácil de leer que negar la prueba. Por ejemplo:

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

es posiblemente más fácil de leer que:

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

Sin embargo, creo que hay algunos enfoques alternativos que son mejores que un bloque verdadero vacío:

  1. Ponga la condición en una función:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
  2. Ponga la condición dentro de llaves (o paréntesis, pero los paréntesis generan un proceso de subshell y cualquier cambio realizado en el entorno dentro de la subshell no será visible fuera de la subshell) antes de negar:

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
  3. Usar en ||lugar de if:

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

    Prefiero este enfoque cuando la reacción es simple, como afirmar condiciones:

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

En el antiguo caparazón previo a la perforación en versiones antiguas de UNIX, el :comando originalmente estaba destinado a especificar etiquetas para goto(era un comando separado que enrolla la entrada a donde se encuentra la etiqueta, por lo que las etiquetas no podrían ser una sintaxis separada para la que shell sabe que. iftambién era un comando separado.) Pronto se usó para comentarios, antes de que hubiera una sintaxis de comentarios ( #se usó para retroceder) y en estos días existe la compatibilidad tanto como cualquier otra cosa.

Aleatorio832
fuente
0

Además de usarlo como una declaración que no hace nada, puede usarlo para comentar declaraciones individuales convirtiéndolas en argumentos para:.

Martin Stein
fuente
No será exactamente un comentario, ya : echo write this line > myfileque seguirá creando un archivo vacío.
Arcege
55
Como se explica en el enlace de la pregunta, NO: es un mecanismo de comentarios adecuado.
jw013