¿Cuál es el punto de bash Null-operator ":", dos puntos?

13

¿Cuál es el punto del operador "nulo" en un script BASH? Entiendo que se usa como marcador de posición después de un ifcomando cuando no tiene nada que decir, pero necesita un comando para permitir que el programa se ejecute correctamente. Pero, ¿cuál es su uso general? ¿Cuándo lo usarías? ¿Cuándo tiene sentido usarlo?

Justin
fuente
1
La razón por la que cita es muy importante. ¿Por qué necesitas más?
terdon

Respuestas:

16

A veces es útil permitir que ocurran efectos secundarios de expansión de parámetros.

Por ejemplo, establecer un valor predeterminado

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
Glenn Jackman
fuente
2
¿Podría explicar símbolo por símbolo cómo funciona la segunda línea?
Ruslan
Lea sobre el :comando y la expansión de parámetros en el manual de bash.
Glenn Jackman
44
Para describir a qué hace referencia @glennjackman, la segunda línea llama al comando nulo: y ${name:="John Doe"}se expandirá, lo que hará que la asignación se realice porque se lee como un argumento para:. Sin el: el shell intentará ejecutar "John Doe" como un comando, o el valor $namesi ya está configurado
imkendal
13

También puedes usarlo para bucles sin fin:

while : ; do 
   # ....
done
choroba
fuente
44
Pero tal vez while truesea ​​más legible, porque (a) usa menos puntuación y (b) es más similar a los lenguajes derivados de C.
wchargin
9

Puede usarlo para crear un archivo sin ejecutar un programa ::

: > /path/to/file

Esto es infinitamente más rápido que touch /path/to/file (ya que no requiere ejecutar el touchprograma) y puede ser marginalmente más portátil que simplemente

> /path/to/file

que parece funcionar en muchos sistemas. Del mismo modo, se puede usar para verificar si tiene acceso de escritura a un archivo :

if { : >> /path/to/file;} 2> /dev/null
then
    echo "writeable"
else
    echo "write permission denied"
fi

aunque esto, también, generalmente se puede hacer sin el :. Advertencias:

  • Esto no verifica si el archivo ya existe. Si no lo hace, esto creará el archivo si tiene permiso para hacerlo.
  • Si el archivo no existe y su script no tiene permiso para crearlo, esto informará "permiso de escritura denegado".

(Consulte la pregunta vinculada para conocer las razones por las cuales esto es más confiable que if [ -w /path/to/file ]).

G-Man dice 'restablecer a Mónica'
fuente
5

Hace mucho tiempo, en Unix V6 y Thompson Shell, el :realmente se usó como parte de la gotodeclaración. Según el manual , apareció originalmente en la versión 3 de Unix:

Se busca en el archivo de comando completo una línea que comience con: como el primer carácter no en blanco, seguido de uno o más espacios en blanco y luego la etiqueta. Si se encuentra dicha línea, goto reposiciona el desplazamiento del archivo de comando a la línea después de la etiqueta y sale. Esto hace que el shell se transfiera a la línea etiquetada.

Hoy en día, en bash, se utiliza como operador sin operaciones, devolviendo el éxito. De hecho, si nos fijamos en el código fuente , verá que tanto truey :utilizar la misma función, int colon_builtin(), debajo. No hay :un comando no incorporado, y en /bin/truerealidad es un comando bastante grande para lo que hace.

:podría usarse en cualquier lugar true, por ejemplo command_that_can_fail || true, en , aunque es probable que confunda a los no expertos. Lea más sobre esto aquí .

Sergiy Kolodyazhnyy
fuente
3

Puede usarlo en la prueba positiva de un ifcomando cuando solo desea hacer algo en el lado negativo. Por ejemplo:

if [[ True == False ]]; then
    :
else
    echo "true <> flase"
fi

Sin el :bash generaría un error de sintaxis.

Este es un ejemplo demasiado simplificado. En general, usaría una técnica de este tipo en la codificación preliminar cuando aún no haya escrito ese segmento de código y solo necesite algo que no genere un error.

WinEunuuchs2Unix
fuente
Buena respuesta, aunque puede no ser aparente al principio, que esto es más útil con un comando real dentro de la condición de prueba, por ejemplo if pgrep firefox >/dev/null ; then : ; else echo "Firefox not running"; fi, mostrará un error solo si Firefox no se está ejecutando. En otras palabras, cuando necesita hacer algo solo cuando el comando tiene un error. En cierto modo, esto es equivalente pgrep firefox || echo "Firefox not running", aunque más legible y permite más comandos
Sergiy Kolodyazhnyy
0

Acabo de usarlo en un script con comandos SSH para evitar que el script se produzca un error.

En este caso, quiero ver si un usuario puede conectarse a un conjunto de servidores. Si la conexión es correcta, el host remoto hará eco como correcto. Si la conexión falla, SSH responderá con el error. Sin embargo, quiero que mi script salga con 0 y no con el valor del comando SSH si falla. Así que esencialmente atrapo el error SSH al ORARlo ||con el comando nulo :. Se ve como esto:

#!/bin/bash
for i in $(cat servers.txt); do
    echo -n "$i "; 
    ssh user@${i} 'echo OK' || :; 
done

De esa manera obtengo el resultado de SSH pero no el código de error:

....
swl06 ok
swl07 ok
swl08 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
swl09 ok
swl10 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
....
Michael J
fuente