Qual é o utilitário do comando: em shell script, dado que explicitamente não faz nada?

26

Na resposta a esta pergunta sobre comentários em scripts de shell , é indicado que o : é 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?

    
por KennyPeanuts 27.04.2012 / 19:36

8 respostas

18

Eu normalmente uso true em loops; Eu acho que é mais claro:

while true; do
    ...
done

O único lugar que eu achei que : é realmente útil é no caso de declarações, se você precisa combinar algo, mas não quer realmente fazer nada. Por exemplo:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac
    
por 27.04.2012 / 21:01
12

Originalmente, era usado para determinar que era um programa shell da 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, o script será executado em relação a $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.

    
por 27.04.2012 / 20:44
11

: é útil para escrever loops que devem ser terminados de dentro.

while :
do
    ...stuff...
done

Isso será executado para sempre, a menos que break ou exit seja chamado ou o shell receba um sinal de terminação.

    
por 27.04.2012 / 19:52
9

Quando você quer uma instrução "a menos que" em shell script, você usa uma condição "not", que pode parecer ridículo para alguns dos testes, ou usa ':' na cláusula true, com código real em a cláusula falsa.

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

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

    
por 27.04.2012 / 20:37
5

Eu só usei isso em adição ao caracter # para temporariamente comentar uma linha, em uma situação em que comentar a linha produz um erro de sintaxe, devido a um defeito na gramática da shell de não permitir um vazio sequência de comandos:

if condition ; then
    :# temporarily commented out command
fi

Sem o: temos uma seqüência de comando ausente, que é um erro de sintaxe.

    
por 28.04.2012 / 02:01
4

Existem dois casos em que eu 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}"

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

VAR="other value" ./script

A sintaxe ${VAR=value} diz para definir VAR para value se VAR ainda não estiver definido e, em seguida, expandir para o valor da variável. Como ainda não nos importamos com o valor da variável, ela é passada como um argumento para o comando no-op : para descartá-la.

Embora : seja um comando não operacional, a expansão é executada pelo shell (não pelo comando : !) antes de executar o comando : , de forma que a atribuição da variável ainda ocorra (se aplicável).

Também seria aceitável usar true ou algum outro comando em vez de : , mas o código fica 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 da linha printf , a expansão de designaçã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 bloco if real e vazio pode tornar o código mais fácil de ler do que negar o teste. Por exemplo:

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

é mais fácil de ler do que:

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

No entanto, acredito que existam algumas abordagens alternativas melhores do que um bloco verdadeiro 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 parênteses geram um processo de subshell e quaisquer alterações feitas no ambiente dentro da subcamada não serão visíveis fora da subshell) 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 as condições:

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

No antigo shell anterior ao bourne em versões antigas do UNIX, o comando : era originalmente destinado a especificar rótulos para goto (era um comando separado que envia a entrada para o local onde o rótulo é encontrado, para que rótulos não poderia ser uma sintaxe separada que o shell conhecia. if também era um comando separado.) Logo ela foi usada para comentários, antes de haver uma sintaxe de comentário ( # foi usada para backspace) e hoje em dia para compatibilidade, tanto quanto qualquer outra coisa.

    
por 28.04.2012 / 20:03
0

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

    
por 27.04.2012 / 20:26