A que finalidade serve o cólon?

45

Eu hackeei muitos scripts shell e, às vezes, as coisas mais simples me confundem. Hoje, deparei-me com um script que fazia uso extensivo do :bash (dois pontos) incorporado.

A documenação parece bastante simples:

: (a colon)  
     : [arguments]  

Não faça nada além de expandir argumentos e executar redirecionamentos. O status de retorno é zero.

No entanto, eu já vi isso apenas em demonstrações de expansão de shell. O caso de uso no script que eu deparei fez uso extensivo dessa estrutura:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

Na verdade, havia centenas de greps, mas são apenas mais do mesmo. Nenhum redirecionamento de entrada / saída está presente além da estrutura simples acima. Nenhum valor de retorno é verificado posteriormente no script.

Estou lendo isso como uma construção inútil que diz "ou não faça nada". Qual o propósito de terminar com esses "cumprimentos" ou "não fazer nada"? Em que caso essa construção causaria um resultado diferente do que simplesmente deixar de fora || :todas as instâncias?

Caleb
fonte
10
Um possível propósito que posso ver é usar :como alternativa true. Talvez errexitesteja definido e o autor não se importe com o status de saída de alguns comandos.
Jw013
a página vinculada ao Stackoverflow é IMO um pouco mais abrangente (é bom ler esta página e a página vinculada).
Trevor Boyd Smith

Respostas:

29

Parece que os :s no seu script estão sendo usados ​​no lugar true. Se grepnão encontrar uma correspondência no arquivo, ele retornará um código de saída diferente de zero; como jw013 menciona em um comentário, se errexitestiver definido, provavelmente -ena linha shebang, o script sairá se algum dos greps falhar em encontrar uma correspondência. Claramente, não era isso que o autor queria, então ele adicionou || :para tornar o status de saída desse comando composto sempre zero, como o mais comum (na minha experiência) || true/ || /bin/true.

Kevin
fonte
Duh. Isso estava no conceito de um script de construção do RPM e, embora eu não tenha visto nenhum código de saída verificando dentro do script, esqueci de considerar que o processo pai pode estar assistindo.
Caleb
8
Se for esse o caso, eu chamaria isso de má prática de script. É funcionalmente equivalente a usar true, mas a intenção semântica é muito mais clara true. :é mais adequado quando um NOP explícito é desejado.
Jw013
Na minha experiência, essa é uma prática comum em scripts RPM. Provavelmente não deveria estar, mas lá estamos nós.
mattdm
alguns puristas preferem, em :vez de, trueporque :é um bashbuilt-in, onde truenormalmente é um binário compilado com mais sobrecarga. Normalmente eu uso trueporque o código é mais legível (da mesma forma eu prefiro usar em sourcevez de .).
Trevor Boyd Smith
36

O :built-in também é útil com a expansão do shell "atribuir valores padrão" do Bash, onde a expansão é frequentemente usada apenas para o efeito colateral e o valor expandido é descartado:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
Joni
fonte
2
Vim aqui procurando por isso, fiquei perplexo quando vi esse padrão em um script para declarar valores padrão.
ffledgling
21

Posso pensar em dois lugares que usei :no passado.

while :
do
     shell commands
     some exit condition
done

Esse é um ciclo para sempre.

function doSomethingStub {
    :
}

Coloque uma função de esboço, apenas para corrigir o fluxo de controle de nível superior.

Um uso que eu já vi nos velhos tempos: em vez de uma #!/bin/sh(ou qualquer outra) linha, você veria uma :linha. Alguns dos kernels do Real Unix mais antigos ou shells do Real Unix usariam isso para significar "eu sou um script de shell, eles devem me executar". Pelo que me lembro, foi exatamente quando o csh estava fazendo incursões como um shell interativo comum.

Bruce Ediger
fonte
@BruceEdiger: Você tem uma referência à linha "shecolon"?
L0b0 22/03/12
7
Por fim, encontrei uma referência e explicação ": no início de um script": faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger
1
o comportamento no início :é muito estranho. Eu descobri que ele realmente faz com que o script seja executado sh. onde, como quando você inicia o script sem um shebang ... ele tenta executar o script com qualquer shell que esteja sendo executado (por isso, se você estiver executando, bashele tentará executá-lo como bashse tivesse, em cshseguida, ele tentará executá-lo como csh).
Trevor Boyd Smith
19

O :built-in já estava no shell Thompson - foi documentado para o Unix V6 em 1975. No shell Thompson, :indicou um rótulo para o gotocomando. Se você nunca tentou chamar gotouma linha iniciada por , essa linha era efetivamente um comentário.

O shell Bourne , o ancestral dos shells Bourne / POSIX como os conhecemos, nunca teve um gotoque eu saiba, mas foi mantido :como um comando não operacional (já estava presente no Unix V7 ).

Gilles 'SO- parar de ser mau'
fonte
Ponto para informações históricas informativas.
Tony Barganski 9/11
12

Eu descobri uma referência antiga: "O ambiente de programação UNIX" (c) 1984 por Kernighan e Pike.

A página 147 (Programação de shell) diz o seguinte:

":" é um comando interno do shell que não faz nada além de avaliar seus argumentos e retornar "true". Em vez disso [referindo-se a um exemplo de script], poderíamos ter usado true , que simplesmente retorna um status de saída verdadeiro. (Também existe um comando falso .) Mas ':' é mais eficiente que verdadeiro porque não executa um comando do sistema de arquivos . [Itálico / ênfase é minha.]

fracjackmac
fonte
2
Claro, trueagora também é um shell embutido em muitos sistemas.
tripleee 28/02
8

Parece que me lembro que as versões anteriores do shell não tinham uma sintaxe de comentário. Uma linha iniciada com :(que provavelmente teria sido um executável real, semelhante a /bin/true) teria sido a melhor alternativa.

Aqui está uma página de manual para o antigo shell Thompson (sem relação); não há menção a nenhuma sintaxe de comentário.

Keith Thompson
fonte
4
A origem de :era de fato um indicador de etiqueta para o gotocomando, em alguma casca antiga (não sei qual). Um rótulo : somethingpoderia realmente ser usado como um comentário, se não houvesse correspondência goto. A prática continuou mesmo depois de ter gotodesaparecido.
Gilles 'SO- stop be evil'
8

":" é útil para depuração.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Executando normalmente, a função de depuração nunca é executada, portanto, basta passar por cima do noop (variáveis ​​e curingas são expandidos). Se for necessária uma depuração mais aprofundada, remova o noop da variável e a função de depuração será chamada com os argumentos necessários.

Outro uso útil é como um comentário em bloco, que é um recurso ausente da sintaxe do shell.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
Colin
fonte