:è 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.
:>non è un singolo operatore. Potrebbe essere più facile da capire se lo leggi come: > fileinvece.