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:
-
Coloque a condição em uma função:
exotic_condition() { [ -f foo ] && bar || baz; }
if ! exotic_condition; then
do_something_here
fi
-
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
-
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"