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.
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.ExitStatus:Always succeeds.
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:
--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:
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.
:>
não é um único operador. Pode ser mais fácil entender se você o ler como: > file
alternativa.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-r
switchread
.Respostas:
Havia:> em uma linha de um script bash. O que isso significa?
É uma maneira curta de dizer:
file
não existir, crie-o ou trunque-o em0
bytes.Isso significa que você pode ter certeza de que
file
existe e está vazio.Você também pode usar,
> file
mas:> file
é mais portátil.Veja a pergunta Stack Overflow Qual é o objetivo do ':' (dois pontos) GNU Bash Builtin? Para maiores informações.
fonte
otherfile
eecho
as envia parafile
. Ele também cria variáveis do que quer que seja lido ... Se você quiser uma resposta definitiva, faça sua própria pergunta.read
obtém informações de stdin. Por si só, ele lê o que você digita. Como o stdin foi redirecionado para<otherfile
, o conteúdo deotherfile
é "digitado" no stdin. Portanto,read
obtém os valores linha por linha nas variáveis $ A, $ B, $ C, $ D e $ E.truncate
do coreutils?Parece uma maneira elegante de criar um novo arquivo. In
bash
:
é um comando nulo:>
redireciona a saída de:
para um arquivo.fonte
>
faz #:
é uma abreviação detrue
. Possivelmente em algumas conchas,true
não está embutido? Ambos são integrados no bash.:
é outro nome paratrue
. Ambos são shell embutidos no bash, mas não há/bin/:
, apenas um/bin/true
. O redirecionamento de saída causa o shellopen(2)
no arquivoO_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
otherfile
dentro de algumas variáveis nomeadas. O corpo do loop usaecho
para 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. Usarwhile ...;do read -r ...;done <otherfile >file
sugaria menos e evitaria a necessidade de truncar o arquivo primeiro.read -r
nã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 (umaread(2)
chamada de sistema por byte) para evitar ultrapassar o final de uma linha. Seria melhor usar a ferramenta certa para o trabalho:--
significa que seu script não será interrompido seotherfile
for 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 Shellread
atribui 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, poissplit
pode 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
$5
awk, o loop pelos campos ainda perde o espaço em branco original. Minha primeira idéia viável é usargensub
on$0
(a linha inteira) para remover os 4 primeiros campos (ou seja, não espaço seguido de espaço), deixando todo o resto: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
print
antes, mas comtail
no lugar de$5
.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.
fonte