O que esse estranho símbolo ":>" no bash significa


47

Encontrei algo em um script, mas não pertencendo ao script principal. Havia :>uma fila.

Você poderia me explicar o que isso significa?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile

6
Importante, :>não é um único operador. Pode ser mais fácil entender se você o ler como : > filealternativa.
jpfx1342

Isso significa que a pessoa que escreve o roteiro deveria ter redirecionado a saída do loop para o arquivo: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. Ou melhor ainda, eles deveriam ter usado a ferramenta certa para o trabalho, awk, como sugerido por Peter . Como um aparte, você quase sempre deseja usar o -rswitchread .
Tom Fenech 02/09

Fora da festança, seria um sorriso para um corvo.
smci

Respostas:


46

Havia:> em uma linha de um script bash. O que isso significa?

:> file

É uma maneira curta de dizer:

  • Se filenão existir, crie-o ou trunque-o em 0bytes.

Isso significa que você pode ter certeza de que fileexiste e está vazio.

Você também pode usar, > filemas :> fileé mais portátil.

Veja a pergunta Stack Overflow Qual é o objetivo do ':' (dois pontos) GNU Bash Builtin? Para maiores informações.


Eu não entendo a segunda linha. Eu pensei que leu variáveis ​​de leitura. O eco do comando também é estranho. Você poderia explicar?
Diego9403

Eu não sou um especialista em Unix, mas acho que a segunda linha lê as coisas otherfilee echoas envia para file. Ele também cria variáveis ​​do que quer que seja lido ... Se você quiser uma resposta definitiva, faça sua própria pergunta.
DavidPostill

2
@ diego9403: readobtém informações de stdin. Por si só, ele lê o que você digita. Como o stdin foi redirecionado para <otherfile, o conteúdo de otherfileé "digitado" no stdin. Portanto, readobtém os valores linha por linha nas variáveis ​​$ A, $ B, $ C, $ D e $ E.
Slebetman 01/09/2015

Portanto, é apenas uma alternativa mais obscura truncatedo coreutils?
Federico Poloni

11
@ PeterCordes Eu não quis dizer "obscuro" como em "é incomum", mas como em "é menos claro para o leitor".
Federico Poloni

29

Parece uma maneira elegante de criar um novo arquivo. In bash :é um comando nulo:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>redireciona a saída de :para um arquivo.


2
Ele também truncará o arquivo, se ele já existir ...
DavidPostill

2
sim, é isso que >faz #
Arkadiusz Drabczyk

2
:é uma abreviação de true. Possivelmente em algumas conchas, truenão está embutido? Ambos são integrados no bash.
Peter Cordes

12

:é outro nome para true. Ambos são shell embutidos no bash, mas não há /bin/:, apenas um /bin/true. O redirecionamento de saída causa o shell open(2)no arquivo O_CREAT|O_TRUNC. Se nada for escrito, ele permanecerá no comprimento zero.

Juntar essas duas partes :> fileé um idioma bastante comum para truncar arquivos. A maioria das pessoas tentaria torná-lo menos esquisito escrevendo : >file.


Como você perguntou em um comentário sobre a segunda linha, vou transformar meus comentários em uma resposta. (mesmo que você não tenha feito isso na sua pergunta.)

A segunda linha é um loop que lê linhas de otherfiledentro de algumas variáveis ​​nomeadas. O corpo do loop usa echopara imprimi-los com ;separadores em vez do espaço em branco que eles tinham antes. fileé fechado e reaberto (para acrescentar) a cada iteração, porque o redirecionamento está dentro do loop. Usar while ...;do read -r ...;done <otherfile >filesugaria menos e evitaria a necessidade de truncar o arquivo primeiro. read -rnão come \como um personagem de fuga.

O processamento de texto no bash é bastante lento. Parte disso é inevitável: readé preciso ir um byte de cada vez (uma read(2)chamada de sistema por byte) para evitar ultrapassar o final de uma linha. Seria melhor usar a ferramenta certa para o trabalho:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--significa que seu script não será interrompido se otherfilefor nomeado algo parvo --version.

Definir o separador de campos de saída como ;significa que você pode simplesmente passar vários campos como args para imprimir. O Shell readatribui o restante da linha com espaço em branco à última variável, mas não há como dizer ao awk que só se divida em 5. Se isso for importante, talvez continue usando um loop bash, porque é inconveniente no awk. O Perl facilita isso, pois splitpode levar um argumento de max-fields, mas é muito mais lento iniciar do que o awk.

Na verdade, acabou não sendo tão difícil, apenas um regex feio para escrever. Para obter o restante da linha em vez do $5awk, o loop pelos campos ainda perde o espaço em branco original. Minha primeira idéia viável é usar gensubon $0(a linha inteira) para remover os 4 primeiros campos (ou seja, não espaço seguido de espaço), deixando todo o resto:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

Eu entendi direito na primeira tentativa, mas o fato de eu estar impressionado comigo mesmo por isso diz algo sobre a legibilidade desse código awk. >. <

Observe como é o mesmo de printantes, mas com tailno lugar de $5.

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

Isso seria mais impressionante se eu pudesse copiar / colar o literal e mostrar que ele apareceu na saída. Digite um no bash com ^ Q. ctrl-Q significa Citar o próximo pressionamento de tecla como um caractere literal, pois a edição de linha no estilo emacs do bash é igual à emacs real para isso.

O http://mywiki.wooledge.org/BashFAQ possui algumas informações úteis sobre scripts de maneiras que não quebram, independentemente dos dados ou nomes de arquivos que você lança no script.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.