Qual é a utilidade do comando: no script de shell, já que ele explicitamente não faz nada?


27

Na resposta a esta pergunta sobre comentários em scripts de shell , é indicado que :é um comando nulo que explicitamente não faz nada (mas não deve ser usado para comentários).

Qual seria a utilidade de um comando que não faz absolutamente nada?



2
Veja também esta pergunta que tem uma resposta ainda melhor aqui , ou seja, que :é necessário para ser um built-in, enquanto truenão é, o que afeta o escopo de variáveis
— Old Pro

2
Ele explicitamente não faz nada graciosamente .
— Mikeerv

Respostas:


19

Eu normalmente uso trueem loops; Eu acho que é mais claro:

while true; do
    ...
done

O único lugar que achei :realmente útil é o caso, se você precisar corresponder a algo, mas não quiser realmente fazer nada. Por exemplo:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac

3
Concordo. truepara uma condição, :para um NOP.
— Jw013

11
o bash aceita case a in a ) ;; esac. Existem algumas conchas que não aceitam isso?
— Kaz

@Kaz: According to the POSIX shell grammar, case ${var} in value);; *) do_something;; esac is acceptable. The : command is not needed for empty cases.
— Richard Hansen

12

Originalmente, era usado para determinar que era um programa shell Bourne, em oposição ao programa compilado em C. Isso foi antes do shebang e de várias linguagens de script (csh, perl). Você ainda pode executar um script começando com apenas ::

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

Geralmente, ele executa o script contra $SHELL(ou /bin/sh).

Desde então, o principal uso é avaliar os argumentos. Eu ainda uso:

: ${EDITOR:=vim}

para definir um valor padrão em um script.


11

: é útil para gravar loops que devem ser finalizados de dentro.

while :
do
    ...stuff...
done

Isto irá executar sempre a menos breakou exité chamado, ou o shell recebe um sinal de terminação.


3
Eu sinto que while true; do ...; doneComunica intenções para o leitor melhor do quewhile :; do ...; done
— Richard Hansen

9

Quando você deseja uma instrução "a menos que" no script de shell, usa uma condição "não", que pode parecer ridícula para alguns dos testes ou usa ':' na cláusula true, com código real no false cláusula.

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

A "condição exótica" pode ser algo que você não deseja negar, ou isso é muito mais claro se você não usar "lógica negativa".


11
Ele também aparece nos scripts gerados por, autoconfporque é muito mais fácil adicionar um padrão :para ramificações vazias do que descobrir como reverter a condição.
— Dietrich Epp

2
Não consigo ver como ficar furioso !diante de [ some-exotic-condition ]um pateta, mas um supérfluo : elsedepois dele não é pateta.
— Kaz

@Kaz tem um bom argumento. Lembre-se de que é difícil criar condições exóticas. Se você precisar negar tudo, isso é uma coisa, mas isso pode deixar a condição menos clara. Faz um '!' negar toda a condição ou apenas o primeiro termo? É melhor ter uma cláusula ':' true às vezes.
— Bruce Ediger

O !token nega todo um elemento do tubo de comando. while ! grep ... ; do ... done ou if ! [ ... ] ; then ... fi. É basicamente externo à test/[]sintaxe. Veja: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
— Kaz

5

Eu só usei isso além do caractere # para comentar temporariamente uma linha, em uma situação em que comentar a linha produz um erro de sintaxe, devido a um defeito na gramática do shell de não permitir uma sequência vazia de comandos :

if condition ; then
    :# temporarily commented out command
fi

Sem o comando: falta uma sequência de comandos, que é um erro de sintaxe.


4

Há dois casos em que acho :útil:

Atribuições de variável padrão

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

Essa é uma maneira conveniente de permitir que os usuários do seu script shell substituam uma configuração sem editar o script. (No entanto, argumentos de linha de comando são melhores porque você não corre o risco de comportamento inesperado se o usuário tiver coincidentemente a variável que você usa no ambiente exportado.) Veja como o usuário substituirá a configuração:

VAR="other value" ./script

A ${VAR=value}sintaxe diz ao set VARpara valueseVAR já não estiver definida e, em seguida, expanda para o valor da variável. Como ainda não nos importamos com o valor da variável, ela é passada como argumento ao comando no-op :para jogá-la fora.

Mesmo sendo :um comando não operacional, a expansão é realizada pelo shell (não pelo: comando!) Antes de executar o comando: comando, para que a atribuição de variável ainda ocorra (se aplicável).

Também seria aceitável usar trueou algum outro comando em vez de: , mas o código se torna mais difícil de ler porque a intenção é menos clara.

O script a seguir também funcionaria:

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

Mas o acima é muito mais difícil de manter. Se uma linha usando ${VAR}for adicionada acima dessa printflinha, a expansão da atribuição padrão deverá ser movida. Se o desenvolvedor esquecer de mover essa atribuição, um bug será introduzido.

Algo para colocar em um bloco condicional vazio

Blocos condicionais vazios geralmente devem ser evitados, mas às vezes são úteis:

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

Algumas pessoas argumentam que ter um ifbloco verdadeiro vazio pode facilitar a leitura do código do que negar o teste. Por exemplo:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

é sem dúvida mais fácil de ler do que:

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

No entanto, acredito que existem algumas abordagens alternativas que são melhores do que um verdadeiro bloco vazio:

  1. Coloque a condição em uma função:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
  2. Coloque a condição dentro de chaves (ou parênteses, mas os parênteses geram um processo de subcamação e todas as alterações feitas no ambiente dentro da subcamada não serão visíveis fora dela) antes de negar:

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
  3. Use em ||vez de if:

    [ -f foo ] && bar || baz || {
        do_something_here
    }

    Eu prefiro essa abordagem quando a reação é simples, como afirmar condições:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"

1

No antigo shell pré-bourne nas versões antigas do UNIX, o :comando era originalmente destinado a especificar rótulos para goto(era um comando separado que direciona a entrada para onde o rótulo é encontrado, para que rótulos não pudessem ser uma sintaxe separada que o O shell sabe sobre o. iftambém foi um comando separado.) Logo se tornou usado para comentários, antes que houvesse uma sintaxe de comentário ( #era usada para backspace) e hoje em dia existe compatibilidade tanto quanto qualquer outra coisa.


0

Além de usá-lo como uma declaração que não faz nada, você pode usá-lo para comentar declarações únicas, transformando-as em argumentos para:.


Não será exatamente um comentário, pois : echo write this line > myfileainda criará um arquivo vazio.
— Arcege

5
Conforme explicado no link da pergunta, NÃO: é um mecanismo de comentário adequado.
— Jw013
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.