Cosa significa questo strano simbolo “:>” in bash


47

Ho trovato qualcosa in una sceneggiatura, ma non appartenente alla sceneggiatura principale. C'era :>in linea.

Potresti spiegarmi cosa significa?

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

6
È importante sottolineare che :>non è un singolo operatore. Potrebbe essere più facile da capire se lo leggi come : > fileinvece.
jpfx1342,

Ciò significa che la persona che scrive la sceneggiatura avrebbe dovuto reindirizzato l'uscita del loop al file: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. O meglio, avrebbero dovuto usare lo strumento giusto per il lavoro, come suggerito da Peter . Per inciso, quasi sempre si desidera utilizzare l' -rinterruttore conread .
Tom Fenech,

Fuori dalla festa, sarebbe uno smiley per un corvo.
smci,

Risposte:


46

C'era:> in una riga di uno script bash. Cosa significa?

:> file

È una scorciatoia per dire:

  • Se filenon esiste, crearlo altrimenti troncalo in 0byte.

Questo significa che puoi essere sicuro che fileesiste ed è vuoto.

Puoi anche usare > filema :> fileè più portatile.

Vedi la domanda Stack Overflow Qual è lo scopo del ':' (due punti) GNU Bash Builtin? per maggiori informazioni.


Non capisco la seconda riga. Ho pensato, che leggere leggere le variabili. Anche l'eco dei comandi è strana. Potresti spiegare?
diego9403,

Non sono un esperto di Unix ma penso che la seconda riga legga le cose otherfilee echole esca file. Crea anche variabili da qualunque cosa legga ... Se vuoi una risposta definitiva, per favore, fai la tua domanda.
DavidPostill

2
@ diego9403: readottiene input da stdin. Da solo, leggerebbe ciò che scrivi. Poiché lo stdin è stato reindirizzato a, <otherfileil contenuto di otherfileviene "digitato" in stdin. Quindi readottiene i valori riga per riga nelle variabili $ A, $ B, $ C, $ D e $ E.
slebetman,

Quindi è solo un'alternativa più oscura a truncatedai coreutils?
Federico Poloni,

1
@PeterCordes Non intendevo "oscuro" come in "è raro", ma come in "è meno chiaro per il lettore".
Federico Poloni,

29

Sembra un modo elegante di creare un nuovo file. In bash :è un comando null:

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

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>reindirizza l'output di :un file.



2
sì, questo è ciò che >fa
Arkadiusz Drabczyk,

2
:è una scorciatoia per true. Forse in alcune shell, truenon è un builtin? Entrambi sono integrati in bash.
Peter Cordes,

12

:è un altro nome per true. Entrambi sono builtin della shell in bash, ma non c'è /bin/:, solo a /bin/true. Il reindirizzamento dell'output provoca la shell open(2)nel file con O_CREAT|O_TRUNC. Se non viene scritto nulla, rimane a lunghezza zero.

Mettere insieme questi due pezzi :> fileè un linguaggio abbastanza comune per troncare i file. La maggior parte delle persone cercherebbe di renderlo meno strano scrivendo : >file, però.


Dato che hai chiesto in un commento sulla seconda riga, trasformerò i miei commenti in una risposta. (anche se non l'hai posto nella tua domanda.)

La seconda riga è un ciclo che legge le righe otherfilein alcune variabili denominate. Il corpo del loop viene utilizzato echoper stamparli con ;separatori invece di qualsiasi spazio bianco avessero prima. fileviene chiuso e riaperto (per aggiungere) ogni iterazione, poiché il reindirizzamento si trova all'interno del ciclo. L'utilizzo while ...;do read -r ...;done <otherfile >filefarebbe meno schifo ed eviterebbe prima la necessità di troncare il file. read -rnon mangia \come personaggio di fuga.

L'elaborazione del testo in bash è piuttosto lenta. Parte di ciò è inevitabile: readdeve passare un byte alla volta (una read(2)chiamata di sistema per byte) per evitare di superare la fine di una linea. Sarebbe meglio usare lo strumento giusto per il lavoro:

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

--significa che la tua sceneggiatura non si rompe se otherfilesi chiama qualcosa di stupido --version.

Impostando Output Field Separator su ;significa che puoi semplicemente passare più campi come args per stampare. Shell readassegna l'intero resto della linea con spazi bianchi all'ultima variabile, ma non c'è modo di dire a awk di dividere solo in 5. Se questo è importante, forse continua a usare un loop bash, perché è scomodo in awk. Perl lo rende facile, dal momento che splitpuò richiedere un argomento max-fields, ma è molto più lento avviarlo che awk.

In realtà, non è stato così difficile, solo una brutta regex da scrivere. Per ottenere il resto della linea anziché $5in awk, il looping sui campi perde ancora il loro spazio bianco originale. La mia prima idea praticabile è quella di usare gensubsu $0(l'intera linea) per rimuovere i primi 4 campi (cioè non spazio seguito da spazio), lasciando tutto il resto:

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

Ho capito bene al primo tentativo, ma il fatto che sono rimasto impressionato da me stesso per questo dice qualcosa sulla leggibilità di quel codice awk. >. <

Nota come è lo stesso printdi prima, ma con tailal posto di $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

Questo sarebbe più impressionante se potessi copiare / incollare il letterale e mostrare che è arrivato nell'output. Digita uno in bash con ^ Q. ctrl-Q significa citare il prossimo tasto premuto come carattere letterale, dal momento che l'editing delle linee in stile emacs di bash è lo stesso degli emacs reali per questo.

http://mywiki.wooledge.org/BashFAQ ha alcune cose utili sullo scripting in modi che non si romperanno, indipendentemente dai dati o dai nomi dei file che lanci allo script.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.