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 VAR
para value
seVAR
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 true
ou 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 printf
linha, 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 if
bloco 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:
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 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
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"