¿Cuál es el propósito de un comando que no hace nada, es poco más que un líder de comentarios, pero en realidad es un shell integrado en sí mismo?
Es más lento que insertar un comentario en sus scripts en aproximadamente un 40% por llamada, lo que probablemente varía mucho según el tamaño del comentario. Las únicas razones posibles que puedo ver son:
# 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
Supongo que lo que realmente estoy buscando es qué aplicación histórica podría haber tenido.
Respuestas:
Históricamente , los shells Bourne no tenían
true
yfalse
como comandos incorporados.true
en su lugar, simplemente se le asignó un alias:
yfalse
algo parecidolet 0
.:
es un poco mejor que latrue
portabilidad a las antiguas conchas derivadas de Bourne. Como un ejemplo simple, considere no tener ni el!
operador de la tubería ni el||
operador de la lista (como fue el caso de algunas conchas de Bourne antiguas). Esto deja laelse
cláusula de laif
declaración como el único medio para bifurcar según el estado de salida:Dado que
if
requiere unathen
cláusula no vacía y los comentarios no cuentan como no vacíos,:
sirve como no operativo.Hoy en día (es decir: en un contexto moderno) generalmente puede usar cualquiera
:
otrue
. Ambos están especificados por POSIX, y algunos encuentrantrue
más fácil de leer. Sin embargo, hay una diferencia interesante::
es un llamado POSIX integrado especial , mientras quetrue
es un incorporado normal .Se requieren incorporaciones especiales para integrarse en el shell; Las incorporaciones regulares solo están incorporadas "típicamente", pero no están estrictamente garantizadas. Por lo general, no debería haber un programa normal denominado
:
con la funcióntrue
en PATH de la mayoría de los sistemas.Probablemente, la diferencia más crucial es que con las funciones integradas especiales, cualquier variable establecida por la función incorporada, incluso en el entorno durante la evaluación de comandos simples, persiste después de que se completa el comando, como se demuestra aquí usando ksh93:
Tenga en cuenta que Zsh ignora este requisito, al igual que GNU Bash, excepto cuando se opera en modo de compatibilidad POSIX, pero todos los demás shells principales "derivados de POSIX sh" lo observan, incluidos dash, ksh93 y mksh.
Otra diferencia es que las funciones integradas regulares deben ser compatibles con
exec
- demostradas aquí usando Bash:POSIX también señala explícitamente que
:
puede ser más rápido quetrue
, aunque esto es, por supuesto, un detalle específico de implementación.fuente
exec
?true
es una construcción regular, pero es incorrecto porqueexec
está usando en/bin/true
lugar de la construcción.: ${var?not initialized}
et al.:
es una función especial incorporada y que no debería tener una función nombrada por ella. ¿Pero no es el ejemplo más comúnmente visto de la bomba tenedor:(){ :|: & };:
nombrando una función con nombre:
?Lo uso para habilitar / deshabilitar fácilmente comandos variables:
Así
Esto lo convierte en un script limpio. Esto no se puede hacer con '#'.
También,
es una de las formas más simples de garantizar que existe 'afile' pero tiene una longitud de 0.
fuente
>afile
es aún más simple y logra el mismo efecto.vecho=":"
? ¿Solo por legibilidad?Una aplicación útil para: es si solo está interesado en usar expansiones de parámetros para sus efectos secundarios en lugar de pasar su resultado a un comando. En ese caso, utiliza el PE como argumento para: o falso dependiendo de si desea un estado de salida de 0 o 1. Un ejemplo podría ser
: "${var:=$1}"
. Como:
es una construcción, debería ser bastante rápido.fuente
: $((a += 1))
(++
y los--
operadores no necesitan implementarse de acuerdo con POSIX). En bash, ksh y otros shells posibles también puede hacerlo:((a += 1))
o((a++))
pero POSIX no lo especifica.(())
se especifica como una característica opcional. "Si una secuencia de caracteres que comienza con" (("sería analizada por el shell como una expansión aritmética precedida por un '$', los shells que implementan una extensión por la cual" ((expresión)) "se evalúa como una expresión aritmética pueden tratar el "((" como introducción como una evaluación aritmética en lugar de un comando de agrupación. ":
También puede ser para comentarios de bloque (similar a / * * / en lenguaje C). Por ejemplo, si desea omitir un bloque de código en su secuencia de comandos, puede hacer esto:fuente
\
escapar de cualquiera de los caracteres delimitadores para el mismo efecto:: <<\SKIP
.Si desea truncar un archivo a cero bytes, útil para borrar registros, intente esto:
fuente
> file.log
Es más simple y logra el mismo efecto.:>
es más portátil. Algunos shells (como myzsh
) crean una instancia automática de un gato en el shell actual y escuchan el stdin cuando reciben una redirección sin comando. En lugar de esocat /dev/null
,:
es mucho más simple. A menudo, este comportamiento es diferente en shells interactivos en lugar de scripts, pero si escribe el script de una manera que también funciona de forma interactiva, la depuración mediante copiar y pegar es mucho más fácil.: > file
difieren detrue > file
(aparte del recuento de caracteres y la cara feliz) en una cáscara moderna (asumiendo:
ytrue
son igual de rápido)?Es similar a
pass
en Python.Un uso sería desactivar una función hasta que se escriba:
fuente
Dos usos más no mencionados en otras respuestas:
Inicio sesión
Tome este script de ejemplo:
La primera línea,
set -x
hace que el shell imprima el comando antes de ejecutarlo. Es una construcción bastante útil. La desventaja es que elecho Log message
tipo habitual de declaración ahora imprime el mensaje dos veces. El método de los dos puntos se resuelve. Tenga en cuenta que aún tendrá que escapar de caracteres especiales como lo haría paraecho
.Cron puestos de trabajo
He visto que se usa en trabajos cron, como este:
Este es un trabajo cron que ejecuta el script
/opt/backup.sh
todos los días a las 10:45. La ventaja de esta técnica es que mejora el aspecto de los correos electrónicos cuando/opt/backup.sh
imprime algún resultado.fuente
set -x
, los comandos impresos (incluyendo algo así: foobar
) van a stderr.Puede usarlo junto con backticks (
``
) para ejecutar un comando sin mostrar su salida, de esta manera:Por supuesto que podrías hacerlo
some_command > /dev/null
, pero la:
versión es algo más corta.Dicho esto, no recomendaría hacerlo, ya que confundiría a las personas. Simplemente me vino a la mente como un posible caso de uso.
fuente
También es útil para programas políglotas:
Esto es ahora tanto un shell-script ejecutable y un programa JavaScript: significado
./filename.js
,sh filename.js
ynode filename.js
todo el trabajo.(Definitivamente un uso un poco extraño, pero efectivo de todos modos).
Alguna explicación, según lo solicitado:
Los scripts de shell se evalúan línea por línea; y el
exec
comando, cuando se ejecuta, finaliza el shell y reemplaza su proceso con el comando resultante. Esto significa que para el shell, el programa se ve así:Mientras no se produzca una expansión o alias de parámetros en la palabra, cualquier palabra en un script de shell se puede incluir entre comillas sin cambiar su significado; esto significa que
':'
es equivalente a:
(solo lo hemos incluido entre comillas aquí para lograr la semántica de JavaScript que se describe a continuación)... y como se describió anteriormente, el primer comando en la primera línea es un no-op (se traduce
: //
, o si prefiere citar las palabras':' '//'
,. Observe que//
aquí no tiene un significado especial, como lo hace en JavaScript; es solo una palabra sin sentido que se está desechando).Finalmente, el segundo comando en la primera línea (después del punto y coma), es la verdadera carne del programa: es la
exec
llamada que reemplaza el script de shell que se invoca , con un proceso Node.js invocado para evaluar el resto del script.Mientras tanto, la primera línea, en JavaScript, se analiza como un literal de cadena (
':'
), y luego un comentario, que se elimina; así, a JavaScript, el programa se ve así:Dado que el literal de cadena está en una línea por sí mismo, es una declaración no operativa y, por lo tanto, se elimina del programa; eso significa que se elimina toda la línea, dejando solo su código de programa (en este ejemplo, el
function(){ ... }
cuerpo).fuente
: //;
y~function(){}
hacer? Gracias:)
~function(){}
, eso es un poco más complicado. Hay un par de otras respuestas aquí que lo tocan, aunque ninguna de ellas realmente lo explica a mi satisfacción ... si ninguna de esas preguntas lo explica lo suficientemente bien para usted, no dude en publicarlo como una pregunta aquí, estaré feliz de responder en profundidad sobre una nueva pregunta.node
. ¡Entonces la parte de la función tiene que ver con javascript! Estoy bien con el operador unario frente a IIFE. En primer lugar, pensé que esto también era bash y que en realidad no entendí el significado de tu publicación. Estoy bien ahora, ¡gracias por su tiempo dedicado a agregar "desglose"!~{ No problem. (= }
Funciones de autodocumentación
También puede usar
:
para incrustar documentación en una función.Suponga que tiene un script de biblioteca
mylib.sh
, que proporciona una variedad de funciones. Puede obtener la biblioteca (. mylib.sh
) y llamar a las funciones directamente después de eso (lib_function1 arg1 arg2
), o evitar abarrotar su espacio de nombres e invocar la biblioteca con un argumento de función (mylib.sh lib_function1 arg1 arg2
).¿No sería bueno si también pudiera escribir
mylib.sh --help
y obtener una lista de funciones disponibles y su uso, sin tener que mantener manualmente la lista de funciones en el texto de ayuda?Algunos comentarios sobre el código:
declare -f
para enumerar todas las funciones disponibles, luego las filtra a través de sed para mostrar solo las funciones con el prefijo apropiado.mylib.sh function1
y se traduce internamentelib_function1
. Este es un ejercicio que le queda al lector.$1
. Al mismo tiempo, desordenará su espacio de nombres si obtiene la biblioteca. Si no le gusta, puede cambiar el nombre a algo parecidolib_help
o verificar los argumentos--help
en el código principal e invocar la función de ayuda manualmente.fuente
Vi este uso en un script y pensé que era un buen sustituto para invocar a basename dentro de un script.
... este es un reemplazo para el código:
basetool=$(basename $0)
fuente
basetool=${0##*/}