Qual é o objetivo do operador nulo do bash “:”, dois pontos?

13

Qual é o objetivo do operador "nulo" em um script BASH? Entendo que ele é usado como um espaço reservado após um ifcomando quando você não tem nada a dizer, mas precisa de um comando para permitir que o programa seja executado corretamente. Mas qual é o uso geral para isso? Quando você o usaria? Quando faz sentido usá-lo?

Justin
fonte
1
A razão que você cita é bastante importante. Por que você precisa de mais?
terdon

Respostas:

16

Às vezes, é útil permitir que ocorram efeitos colaterais de expansões de parâmetros.

Por exemplo, definindo um valor padrão

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
Glenn Jackman
fonte
2
Você poderia explicar símbolo por símbolo como a segunda linha funciona?
Ruslan
Leia sobre a expansão de :comandos e parâmetros no manual do bash.
Glenn Jackman
4
Para descrever o que @glennjackman está fazendo referência, a segunda linha chama o comando nulo:, e ${name:="John Doe"}será expandida, fazendo com que a atribuição ocorra porque é lida como um argumento para:. Sem o: o shell tentará executar "John Doe" como um comando, ou o valor, $namese já estiver definido
imkendal 07/07
13

Você também pode usá-lo para loops infinitos:

while : ; do 
   # ....
done
choroba
fonte
4
Mas talvez while trueseja mais legível, porque (a) usa menos pontuação e (b) é mais semelhante às linguagens derivadas de C.
wchargin
9

Você pode usá-lo para criar um arquivo sem executar um programa:

: > /path/to/file

Isso é infinitesimalmente mais rápido que touch /path/to/file (já que não requer a execução do touchprograma) e pode ser marginalmente mais portátil do que simplesmente

> /path/to/file

o que parece funcionar em muitos sistemas. Da mesma forma, ele pode ser usado para verificar se você tem acesso de gravação a um arquivo :

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

embora isso também possa geralmente ser feito sem o :. Ressalvas:

  • Isso não verifica se o arquivo já existe. Caso contrário, isso criará o arquivo se tiver permissão para fazê-lo.
  • Se o arquivo não existir e seu script não tiver permissão para criá-lo, isso informará "permissão de gravação negada".

(Veja a pergunta vinculada por motivos pelos quais isso é mais confiável do que if [ -w /path/to/file ].)

G-Man diz que 'restabelece Monica'
fonte
5

No caminho de volta, no Unix V6 e Thompson Shell, o :foi realmente usado como parte da gotodeclaração. De acordo com o manual , ele apareceu originalmente na versão 3 do Unix:

O arquivo de comando inteiro é procurado por uma linha que começa com a: como o primeiro caractere que não está em branco, seguido por um ou mais espaços em branco e, em seguida, o rótulo. Se essa linha for encontrada, goto reposiciona o deslocamento do arquivo de comando para a linha após o rótulo e sai. Isso faz com que o shell seja transferido para a linha rotulada.

Atualmente, bashele é usado como um operador não operacional, retornando sucesso. De fato, se você olhar para o código fonte , verá que ambos truee :usam a mesma função int colon_builtin(), embaixo. Não existe :um comando não integrado e, /bin/truena verdade , é um comando bastante grande para o que ele faz.

:pode ser usado em qualquer lugar true, por exemplo command_that_can_fail || true, embora isso possa confundir não especialistas. Leia mais sobre isso aqui .

Sergiy Kolodyazhnyy
fonte
3

Você pode usá-lo no teste positivo de um ifcomando quando quiser apenas fazer algo do lado negativo. Por exemplo:

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

Sem o :bash, geraria um erro de sintaxe.

Este é um exemplo simplificado demais. Geralmente, você usaria essa técnica na codificação preliminar quando ainda não escreveu esse segmento de código e precisa apenas de algo que não gere um erro.

WinEunuuchs2Unix
fonte
Boa resposta, embora possa não parecer aparente a princípio, que isso é mais útil com um comando real dentro da condição de teste, por exemplo if pgrep firefox >/dev/null ; then : ; else echo "Firefox not running"; fi, mostraria erro apenas se o Firefox não estivesse em execução. Em outras palavras, quando você precisa fazer algo apenas quando o comando tem um erro. De certa forma isso é equivalente a pgrep firefox || echo "Firefox not running", embora mais legível e permite mais comandos
Sergiy Kolodyazhnyy
0

Acabei de usá-lo em um script com comandos SSH para evitar erros no script.

Nesse caso, quero ver se um usuário pode se conectar a um conjunto de servidores. Se a conexão estiver OK, o host remoto ecoará OK. Se a conexão falhar, o SSH responderá com o erro. No entanto, quero que meu script saia com 0 e não com o valor do comando SSH, se ele falhar. Então, basicamente eu intercepto o erro SSH ORing ||com o comando nulo :. Se parece com isso:

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

Dessa forma, recebo a saída do SSH, mas não o código de erro:

....
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
fonte