¿Para qué sirve el colon incorporado?

45

He pirateado muchos scripts de shell, y a veces las cosas más simples me desconciertan. Hoy me encontré con un script que hizo un uso extenso del :bash (colon) incorporado.

La documentación parece bastante simple:

: (a colon)  
     : [arguments]  

No haga nada más que expandir argumentos y realizar redireccionamientos. El estado de retorno es cero.

Sin embargo, anteriormente solo he visto esto usado en demostraciones de expansión de shell. El caso de uso en el script que encontré hizo un uso extenso de esta estructura:

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

En realidad, había cientos de greps, pero son más de lo mismo. No hay redireccionamientos de entrada / salida presentes aparte de la estructura simple anterior. No se verifican valores de retorno más adelante en el script.

Estoy leyendo esto como una construcción inútil que dice "o no hacer nada". ¿Para qué sirve terminar estos greps con "o no hacer nada"? ¿En qué caso esta construcción causaría un resultado diferente que simplemente dejar de lado || :todas las instancias?

Caleb
fuente
10
Un posible propósito que puedo ver es usar :como alternativa a true. Tal vez errexitestá configurado y al autor no le importa el estado de salida de algunos comandos.
jw013
la página enlazada de Stackoverflow es IMO un poco más completa (muy bueno para leer tanto esta página como la página enlazada).
Trevor Boyd Smith

Respuestas:

29

Parece que los :s en su secuencia de comandos se están utilizando en lugar de true. Si grepno encuentra una coincidencia en el archivo, devolverá un código de salida distinto de cero; Como menciona jw013 en un comentario, si errexitse establece, probablemente -een la línea shebang, el script se cerraría si alguno de los greps no logra encontrar una coincidencia. Claramente, eso no es lo que el autor quería, por lo que agregó || :que el estado de salida de ese comando compuesto en particular siempre es cero, como el más común (en mi experiencia) || true/ || /bin/true.

Kevin
fuente
Duh Esto estaba en el concepto de un script de compilación RPM, y aunque no vi ningún código de salida que se verificara dentro del script, olvidé considerar que el proceso principal podría estar mirando.
Caleb
8
Si ese es el caso, lo llamaría una mala práctica de secuencias de comandos. Es funcionalmente equivalente a usar en su truelugar, pero la intención semántica es mucho más clara true. :es más adecuado cuando se desea un NOP explícito.
jw013
En mi experiencia, esta es una práctica común en los scripts RPM. Probablemente no debería ser así, pero ahí estamos.
mattdm
algunos puristas prefieren en :lugar de trueporque :es una función bashincorporada, como truesuele ser un binario compilado con más sobrecarga. generalmente lo uso trueporque el código es más legible (del mismo modo, prefiero usarlo en sourcelugar de .).
Trevor Boyd Smith
36

El :builtin también es útil con la expansión de shell Bash "asignar valores predeterminados", donde la expansión a menudo se usa únicamente para el efecto secundario y el valor expandido se desecha:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
Joni
fuente
2
Vine aquí buscando esto, estaba desconcertado cuando vi este patrón en un script para declarar valores predeterminados.
incipiente
21

Puedo pensar en dos lugares que he usado :en el pasado.

while :
do
     shell commands
     some exit condition
done

Ese es un ciclo para siempre.

function doSomethingStub {
    :
}

Ponga una función stub, solo para obtener el flujo de control de nivel superior correcto.

Un uso que he visto en los viejos tiempos: en lugar de una línea #!/bin/sh(o lo que sea), verías una :línea. Algunos de los núcleos más antiguos de Real Unix o shells de Real Unix usarían eso para significar "Soy un script de shell, me han ejecutado". Como recuerdo, esto fue justo cuando csh estaba haciendo incursiones como un shell interactivo común.

Bruce Ediger
fuente
@BruceEdiger: ¿Tiene alguna referencia a la línea "shecolon"?
l0b0
77
Finalmente encontré una referencia y explicación ": al comienzo de un script": faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger
1
El comportamiento al principio :es muy extraño. descubrí que efectivamente hace que se ejecute el script sh. donde, como cuando inicia el script sin un shebang ... intenta ejecutar el script con cualquier shell que se esté ejecutando (por lo que si está ejecutando bash, intenta ejecutarlo como bashsi tuviera, cshentonces intenta ejecutarlo como csh).
Trevor Boyd Smith
19

El :incorporado ya estaba en el shell de Thompson : está documentado para Unix V6 en 1975. En el shell de Thompson, :indicaba una etiqueta para el gotocomando. Si nunca intentó llamar gotoa una línea que comienza , esa línea fue efectivamente un comentario.

El shell Bourne , el antepasado de los shells Bourne / POSIX tal como los conocemos, nunca tuvo uno gotoque yo sepa, pero se mantuvo :como un comando no operativo (ya estaba presente en Unix V7 ).

Gilles 'SO- deja de ser malvado'
fuente
Punto para antecedentes históricos informativos.
Tony Barganski
12

Saqué una vieja referencia: "El entorno de programación UNIX" (c) 1984 de Kernighan y Pike.

La página 147 (Programación de Shell) dice esto:

":" es un comando incorporado de shell que no hace más que evaluar sus argumentos y devolver "verdadero". En cambio [refiriéndose a un ejemplo de script], podríamos haber usado true , que simplemente devuelve un estado de salida verdadero. (También hay un comando falso ). Pero ':' es más eficiente que verdadero porque no ejecuta un comando desde el sistema de archivos . [Cursiva / énfasis es mío.]

fracjackmac
fuente
2
Por supuesto, trueahora también es un shell integrado en muchos sistemas.
tripleee
8

Me parece recordar que las primeras versiones del shell no tenían una sintaxis de comentarios. Una línea que comience con :(que probablemente habría sido un ejecutable real, similar a /bin/true) habría sido la mejor alternativa.

Aquí hay una página de manual para el antiguo caparazón de Thompson (sin relación); no se menciona ninguna sintaxis de comentarios.

Keith Thompson
fuente
44
El origen de :hecho fue un indicador de etiqueta para el gotocomando, en algún shell antiguo (no sé cuál). De hecho, una etiqueta : somethingpodría usarse como un comentario, si no hubiera coincidencia goto. La práctica se mantuvo incluso después de gotodesaparecer.
Gilles 'SO- deja de ser malvado'
8

":" es útil para la depuración.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Al ejecutarse normalmente, la función de depuración nunca se ejecuta, por lo que sh solo pasa por encima del noop (aunque las variables y los comodines se expanden). Si se requiere una depuración más profunda, elimine el noop de la variable y se llama a la función de depuración con los argumentos necesarios.

Otro uso útil es como un comentario de bloque, que es una característica que falta en la sintaxis de shell.

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