1 puntos por GN⁺ 2 시간 전 | 1 comentarios | Compartir por WhatsApp
  • En el shell, : es un comando nulo (null command) que no hace nada y solo evalúa sus argumentos; combinado con la expansión de parámetros permite manejar de forma concisa la validación de argumentos obligatorios y la asignación de valores por defecto
  • : "${1:?missing argument, aborting!}" hace que, si $1 no existe o está vacío, se imprima un mensaje de diagnóstico en stderr y se termine con un estado distinto de 0
  • Si pasas ${VAR:=default} como argumento de :, la expansión se ejecuta pero la cadena resultante se descarta, así que no se intenta ejecutar el resultado como comando y solo se asigna el valor por defecto
  • : también puede usarse para vaciar archivos y verificar accesibilidad mediante redirección, como comando vacío en trap, para comprobar variables con set -u, y en ramas condicionales vacías
  • : "${VAR:=default}" escribe el nombre de la variable una sola vez, reduciendo la posibilidad de errores tipográficos, y en while : funciona como una condición que siempre tiene éxito para expresar un bucle infinito

Comando nulo y expansión de parámetros

  • : es un comando integrado de comando nulo que evalúa sus argumentos y luego descarta el resultado
    • Se remonta hasta el Thompson shell de 1971, donde también se usaba como etiqueta y como el primer marcador de comentarios de Unix
  • En lugar de un condicional de cuatro líneas, puedes validar un argumento obligatorio con esta sola línea
: "${1:?missing argument, aborting!}"
echo "Hello $1!"
  • La sintaxis de expansión de parámetros ${name:?diagnostic} comprueba si $name no está definido o está vacío
    • Si no tiene valor, imprime diagnostic en stderr y termina el shell con un estado distinto de 0
    • Si tiene valor, produce el mismo resultado que $name
  • Si ejecutas ${HELLO:=123} sin el comando nulo, el resultado de la expansión, 123, se trata como un comando y provoca command not found
    • : ${HELLO:=123} evalúa la expansión, asigna HELLO=123 y luego descarta el resultado
  • : "${DATA_DIR:=/var/data}" reduce la posibilidad de un error tipográfico como DATA_DRI porque, a diferencia de DATA_DIR="${DATA_DIR:-/var/data}", solo escribe una vez el nombre de la variable

Formas de aprovechar :

  • Asignar valores por defecto

    • Asigna valores por defecto a variables mientras descarta el resultado de la expansión sin ejecutarlo como comando
: "${DATA_DIR:=/var/data}"
: "${RETRIES:=3}"
  • Vaciar archivos y verificar acceso

    • Combinado con redirección, puede vaciar uno o más archivos
: > error.log
: > error.log > access.log
  • También puedes comprobar si un archivo puede leerse o escribirse usando un subshell y redirección
( : < dataset.json ) && echo YES
( : >> result.json ) && echo YES
  • Donde se necesita un comando vacío

    • Puede usarse cuando la sintaxis requiere un comando, como en trap, pero en realidad no debe hacerse nada
trap : INT
sleep 60
  • También puede colocarse en ramas vacías de un condicional
if some-command; then
    :
else
    echo "command failed"
fi
  • Comprobar varias variables

    • Con set -u activado, permite comprobar de una sola vez si varias variables están definidas
set -u
: "$DEPLOY_ENV" "$HOST"
  • Bucle infinito

    • Como : siempre tiene éxito, permite escribir de forma concisa un bucle infinito
while :; do
  echo "I love colons"
  sleep 1
done

1 comentarios

 
GN⁺ 2 시간 전
Comentarios en Lobste.rs
  • Si configuras el prompt así, aunque copies y pegues toda una línea, la parte del prompt se ignora y solo se ejecuta el comando
    : hayalci@tassadar ~/src/dool ; jj rebase -s dxw -d mrn
    • Inspirado en Plan 9, también usa la opción autocd del shell y el siguiente formato
      ~/directoryname; <command>
      Cada vez que copias una línea de comando del shell, termina haciendo cd al directorio original donde se ejecutó el comando
    • En zsh, lo configura para que al pegar un espacio invisible sin salto de línea borre el contenido de la izquierda
      nbsp=$'\u00A0'  
      PS1="...$nbsp"  
      bindkey -s $nbsp '^u'  
      
  • En los Makefile se usa mucho el colon para mostrar una salida más limpia
    out/%.o: src/%.c  
        @echo CC $@  
        @$(CC) -c -o $@ $<  
    
    De esta forma, make puede ejecutar varios procesos echo al mismo tiempo y escribir en el mismo stream, interfiriéndose entre sí. Si se cambia así, es el propio proceso de make el que imprime y no un proceso hijo
    out/%.o: src/%.c  
        : CC $@  
        @$(CC) -c -o $@ $<  
    
  • Había visto esta técnica en scripts de shell, pero con man : o whatis : era difícil encontrar documentación útil
    Es parecido al comando true, pero se diferencia en que no responde de forma especial a --help, --version, etc., y además tiene menos caracteres
    • Los comandos integrados de Bash hay que buscarlos con help en vez de man
      $ help :  
      :: :  
          Null command.
      
          No effect; the command does nothing.
      
          Exit Status:  
          Always succeeds.  
      
    • En Fish, : es literalmente un alias de true
  • La expansión de parámetros ocurre incluso sin el colon, así que me pregunto por qué hace falta el comando nulo
    • La expansión de parámetros sí ocurre igual, pero si no hay una sintaxis que consuma el resultado, como el comando nulo, el shell trata la cadena expandida como un comando para ejecutar. También agregaron esto al FAQ
      % ${HELLO:=123}  
      zsh: command not found: 123  
      
      % : ${HELLO:=123}  
      % echo $HELLO  
      123  
      
    • El resultado de la cadena interpolada se interpreta como un comando a ejecutar
      #!/bin/sh  
      "${1:?missing argument, aborting!}"  
      
      $ sh foo.sh sh  
      sh-5.3$  
      
  • Cuando voy escribiendo un comando y quiero volver a ejecutarlo más tarde, le pongo un colon al inicio para guardarlo en el historial. Después, al encontrar esa línea en el historial, solo borro el primer carácter y ya puedo ejecutarlo de verdad
    Pero no se me había ocurrido usarlo para los efectos secundarios que surgen al evaluar los argumentos
    • En vez de :, también se puede poner # para guardarlo como comentario. La ventaja, si es algo que piensas ejecutar después, es que las expresiones dentro no se evalúan por adelantado
    • En zsh, con Meta-q o Alt-q puedes apartar temporalmente la línea actual, ejecutar otro comando y, cuando termina, devolver la línea original al búfer de la línea de comandos
      https://nathangrigg.com/2014/04/zsh-push-line-or-edit/
  • En macOS todavía usa Bash 3 y le aparece el siguiente error
    -bash: !}": event not found
    • Le da curiosidad si funciona al quitar el uso de "!"
  • El siguiente código de Con-colon-sion probablemente confunda más a la gente que while true; do...
    while : colons are more than punctuation; do  
      echo "I love colons"  
      sleep 1  
    done  
    
    while true; do solo tiene tres caracteres más que while :; do, así que ya es suficientemente corto, y ese código no parece un ejemplo adecuado para el punto que el autor quiere transmitir
    • No es un ejemplo para seguirlo tal cual, sino un juego de palabras puesto ahí. Si puedes entender este código, entonces ya conoces el comando nulo, y el colon realmente significa más que un simple signo de puntuación
    • Lo que en realidad quería mostrar era un bucle infinito como este, pero al querer hacerlo más ingenioso parece que perdió el punto principal
      while :; do  
          something  
      done