Qual é o propósito de um comando que não faz nada, sendo pouco mais que um líder de comentários, mas na verdade é um shell embutido em si mesmo?
É mais lento do que inserir um comentário em seus scripts em cerca de 40% por chamada, o que provavelmente varia muito, dependendo do tamanho do comentário. As únicas razões possíveis que posso ver são:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true' (lazy programming)
while : ; do command ; done
Acho que o que realmente estou procurando é qual aplicativo histórico ele poderia ter.
Respostas:
Historicamente , os reservatórios Bourne não tinham
true
efalse
como comandos embutidos.true
era simplesmente um alias para:
, efalse
para algo parecidolet 0
.:
é ligeiramente melhor do quetrue
a portabilidade para conchas antigas derivadas de Bourne. Como um exemplo simples, considere não ter o!
operador de pipeline nem o||
operador de lista (como foi o caso de algumas conchas Bourne antigas). Isso deixa aelse
cláusula daif
declaração como o único meio de ramificação com base no status de saída:Como
if
requer umathen
cláusula não vazia e os comentários não contam como não vazios,:
serve como não operacional.Hoje em dia (ou seja: em um contexto moderno), geralmente você pode usar um
:
ou outrotrue
. Ambos são especificados pelo POSIX, e alguns achamtrue
mais fácil de ler. No entanto, há uma diferença interessante::
é o chamado embutido especial POSIX , enquanto o embutidotrue
é regular .É necessário que os embutidos especiais sejam incorporados ao shell; Os embutidos regulares são apenas "tipicamente" embutidos, mas não são estritamente garantidos. Normalmente, não deve haver um programa regular nomeado
:
com a funçãotrue
PATH na maioria dos sistemas.Provavelmente a diferença mais crucial é que, com embutidos especiais, qualquer variável definida pelo embutido - mesmo no ambiente durante uma simples avaliação de comando - persiste após a conclusão do comando, conforme demonstrado aqui usando o ksh93:
Observe que o Zsh ignora esse requisito, assim como o GNU Bash, exceto quando opera no modo de compatibilidade com POSIX, mas todos os outros shells principais "derivados do POSIX sh" observam isso, incluindo dash, ksh93 e mksh.
Outra diferença é que os embutidos regulares devem ser compatíveis com
exec
- demonstrado aqui usando o Bash:O POSIX também observa explicitamente que
:
pode ser mais rápido quetrue
, embora esse seja, obviamente, um detalhe específico da implementação.fonte
exec
?true
é um builtin regular, mas ele está incorreto no queexec
está usando ao/bin/true
invés do builtin.: ${var?not initialized}
et al.:
é um especial incorporado e não deve ter uma função nomeada por ele. Mas não é o exemplo mais comum de fork pump:(){ :|: & };:
nomear uma função com nome:
?Eu o uso para ativar / desativar facilmente comandos variáveis:
portanto
Isso cria um script limpo. Isso não pode ser feito com '#'.
Além disso,
é uma das maneiras mais simples de garantir que 'afile' exista, mas tenha 0 comprimento.
fonte
>afile
é ainda mais simples e alcança o mesmo efeito.vecho=":"
? Apenas por legibilidade?Uma aplicação útil para: é se você estiver interessado apenas em usar expansões de parâmetro para seus efeitos colaterais, em vez de realmente transmitir o resultado para um comando. Nesse caso, você usa o PE como argumento para: ou false, dependendo se você deseja um status de saída de 0 ou 1. Um exemplo pode ser
: "${var:=$1}"
. Como:
é um builtin, deve ser bem rápido.fonte
: $((a += 1))
(++
e os--
operadores não precisam ser implementados de acordo com o POSIX.). No bash, ksh e outros shells possíveis, você também pode fazer:((a += 1))
ou((a++))
mas não é especificado pelo POSIX.(())
seja especificado como um recurso opcional. "Se uma sequência de caracteres iniciada com" (("seria analisada pelo shell como uma expansão aritmética se precedida de um '$'), os shells que implementam uma extensão pela qual" ((expressão)) "são avaliados como uma expressão aritmética podem tratar o "((" como introdução como uma avaliação aritmética em vez de um comando de agrupamento. "):
também pode ser para comentários em bloco (semelhante a / * * / no idioma C). Por exemplo, se você quiser pular um bloco de código no seu script, poderá fazer o seguinte:fonte
\
escapar qualquer um dos caracteres delimitadores para o mesmo efeito:: <<\SKIP
.Se você deseja truncar um arquivo para zero bytes, útil para limpar logs, tente o seguinte:
fonte
> file.log
é mais simples e alcança o mesmo efeito.:>
é mais portátil. Alguns shells (como o meuzsh
) instanciam automaticamente um gato no shell atual e escutam o stdin quando recebem um redirecionamento sem nenhum comando. Em vez decat /dev/null
,:
é muito mais simples. Geralmente, esse comportamento é diferente em shells interativos em vez de scripts, mas se você escrever o script de uma maneira que também funcione de maneira interativa, a depuração por copiar e colar será muito mais fácil.: > file
diferença detrue > file
(além da contagem de caracteres e do rosto feliz) em uma concha moderna (assumindo:
etrue
sendo igualmente rápidos)?É semelhante ao
pass
Python.Um uso seria remover uma função até que ela seja gravada:
fonte
Mais dois usos não mencionados em outras respostas:
Exploração madeireira
Veja este script de exemplo:
A primeira linha
set -x
,, faz com que o shell imprima o comando antes de executá-lo. É uma construção bastante útil. A desvantagem é que oecho Log message
tipo usual de instrução agora imprime a mensagem duas vezes. O método do cólon contorna isso. Observe que você ainda terá que escapar de caracteres especiais como fariaecho
.Cargos Cron
Eu já vi isso sendo usado em tarefas cron, assim:
Este é um trabalho cron que executa o script
/opt/backup.sh
todos os dias às 10:45. A vantagem dessa técnica é que ela cria temas de e-mail com melhor aparência quando a/opt/backup.sh
impressão é impressa.fonte
set -x
, os comandos impressos (incluindo algo como: foobar
) vão para o stderr.Você pode usá-lo em conjunto com backticks (
``
) para executar um comando sem exibir sua saída, assim:Claro que você poderia fazer
some_command > /dev/null
, mas o:
versão-é um pouco mais curta.Dito isto, eu não recomendaria realmente fazer isso, pois apenas confundiria as pessoas. Apenas veio à mente como um possível caso de uso.
fonte
Também é útil para programas poliglotas:
Esta é agora tanto um shell-script executável e um programa JavaScript: o que significa
./filename.js
,sh filename.js
enode filename.js
todo o trabalho.(Definitivamente um pouco de uso estranho, mas eficaz, no entanto.)
Alguma explicação, conforme solicitado:
Os scripts de shell são avaliados linha por linha; e o
exec
comando, quando executado, finaliza o shell e substitui seu processo pelo comando resultante. Isso significa que, para o shell, o programa fica assim:Desde que não ocorra expansão ou alias de parâmetro na palavra, qualquer palavra em um shell-script pode ser colocada entre aspas sem alterar seu significado; isso significa que
':'
é equivalente a:
(apenas o colocamos entre aspas aqui para obter a semântica do JavaScript descrita abaixo)... e, como descrito acima, o primeiro comando na primeira linha é um no-op (traduz para
: //
, ou se você preferir citar as palavras':' '//'
,. Observe que o//
termo não possui significado especial aqui, como ocorre no JavaScript; é apenas uma palavra sem sentido que está sendo jogada fora.)Finalmente, o segundo comando na primeira linha (após o ponto-e-vírgula) é a verdadeira essência do programa: é a
exec
chamada que substitui o shell-script sendo invocado , com um processo Node.js invocado para avaliar o restante do script.Enquanto isso, a primeira linha, em JavaScript, analisa como uma string literal (
':'
) e, em seguida, um comentário, que é excluído; assim, para JavaScript, o programa fica assim:Como o literal da cadeia de caracteres está em uma linha por si só, é uma instrução no-op e, portanto, é retirada do programa; isso significa que a linha inteira é removida, deixando apenas o código do programa (neste exemplo, o
function(){ ... }
corpo).fonte
: //;
e~function(){}
fazer? Obrigado:)
~function(){}
, isso é um pouco mais complicado. Há um par de outras respostas aqui que toque nele, embora nenhum deles realmente explicar isso a minha satisfação ... se nenhuma dessas perguntas explica bem o suficiente para você, sinta-se livre para publicá-la como uma questão aqui, eu vou estar prazer em responder em profundidade sobre uma nova pergunta.node
. Portanto, a parte da função é sobre javascript! Estou bem com o operador unário na frente do IIFE. Eu pensei que isso também era uma festa e, na verdade, realmente não entendi o significado da sua postagem. Eu estou bem agora, obrigado pelo seu tempo gasto adicionando "quebra"!~{ No problem. (= }
Funções de auto-documentação
Você também pode usar
:
para incorporar documentação em uma função.Suponha que você tenha um script de biblioteca
mylib.sh
, fornecendo uma variedade de funções. Você pode originar a biblioteca (. mylib.sh
) e chamar as funções diretamente depois disso (lib_function1 arg1 arg2
) ou evitar sobrecarregar seu espaço de nome e chamar a biblioteca com um argumento de função (mylib.sh lib_function1 arg1 arg2
).Não seria bom se você também pudesse digitar
mylib.sh --help
e obter uma lista de funções disponíveis e seu uso, sem precisar atualizar manualmente a lista de funções no texto de ajuda?Alguns comentários sobre o código:
declare -f
para enumerar todas as funções disponíveis, depois as filtra através do sed para exibir apenas funções com o prefixo apropriado.mylib.sh function1
e é traduzido internamente paralib_function1
. Este é um exercício deixado para o leitor.$1
. Ao mesmo tempo, o espaço para nome será confuso se você for fonte da biblioteca. Se você não gostar disso, poderá alterar o nome para algo comolib_help
ou realmente verificar os argumentos--help
no código principal e chamar a função de ajuda manualmente.fonte
Vi esse uso em um script e pensei que era um bom substituto para invocar o nome de base em um script.
... este é um substituto para o código:
basetool=$(basename $0)
fonte
basetool=${0##*/}