Avvertenza relativa a ">"
I principianti di Unix che hanno appena appreso il reindirizzamento I / O ( <
e >
) spesso provano cose del genere
comando ... input_file > the_same_file
o
comando ... < file > the_same_file
o, quasi equivalentemente,
file cat | comando ...> the_same_file
( grep
, sed
, cut
, sort
, E spell
sono esempi di comandi che le persone sono tentati di utilizzare in costrutti come questi.) Gli utenti sono sorpresi di scoprire che questi scenari il risultato nel file di diventare vuoto.
Una sfumatura che non sembra essere menzionata nell'altra risposta può essere trovata in agguato nella prima frase della sezione Reindirizzamento di bash (1) :
Prima dell'esecuzione di un comando, l'input e l'output possono essere reindirizzati
utilizzando una notazione speciale interpretata dalla shell.
Le prime cinque parole dovrebbero essere in grassetto, corsivo, sottolineato, ingrandito, lampeggiante, colorato di rosso e contrassegnato da un'icona, per sottolineare il fatto che la shell esegue i reindirizzamenti richiesti
prima dell'esecuzione del comando . E ricorda anche
Il reindirizzamento dell'output provoca l'apertura del file ... per la scrittura ... Se il file non esiste, viene creato; se esiste, viene troncato a dimensione zero.
Quindi, in questo esempio:
sort roster > roster
la shell apre il roster
file per la scrittura, troncandolo (ovvero scartando tutto il suo contenuto), prima che il sort
programma inizi a funzionare. Naturalmente, non è possibile fare nulla per recuperare i dati.
Si potrebbe ingenuamente aspettarselo
tr "[:upper:]" "[:lower:]" < poem > poem
potrebbe essere migliore. Poiché la shell gestisce i reindirizzamenti da sinistra a destra, si apre poem
per la lettura (per tr
input standard) prima di aprirla per la scrittura (per output standard). Ma non aiuta. Anche se questa sequenza di operazioni produce due handle di file, entrambi puntano allo stesso file. Quando la shell apre il file per la lettura, i contenuti sono ancora lì, ma vengono comunque bloccati prima dell'esecuzione del programma.
Quindi, cosa fare al riguardo?
Le soluzioni includono:
Controlla se il programma che stai eseguendo ha una propria capacità interna per specificare dove va l'output. Questo è spesso indicato da un -o
(o --output=
) token. In particolare,
sort roster -o roster
è approssimativamente equivalente a
sort roster > roster
tranne, nel primo caso, il sort
programma apre il file di output. Ed è abbastanza intelligente da non aprire il file di output fino a quando non ha letto tutti i file di input.
Allo stesso modo, almeno alcune versioni di sed
hanno un'opzione -i
(modifica i n place) che può essere utilizzata per riscrivere l'output nel file di input (di nuovo, dopo aver letto tutto l'input). Editor come ed
/ ex
, emacs
, pico
, e vi
/ vim
consentono all'utente di modificare un file di testo e salvare il testo modificato nel file originale. Si noti che ed
(almeno) può essere utilizzato in modo non interattivo.
vi
ha una funzione correlata. Se digiti , scriverà il contenuto del buffer di modifica in , leggerà l'output e lo inserirà nel buffer (sostituendo il contenuto originale).:%!command
Entercommand
Semplice ma efficace:
comando ... input_file > temp_file && mv temp_file input_file
Questo ha lo svantaggio che, se input_file
è un collegamento, sarà (probabilmente) sostituito da un file separato. Inoltre, il nuovo file sarà di tua proprietà, con protezioni predefinite. In particolare, ciò comporta il rischio che il file finisca per essere leggibile in tutto il mondo, anche se l'originale input_file
non lo era.
variazioni:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
che lascerà comunque (potenzialmente) temp_file
leggibile il mondo. Anche meglio:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Ciò preserva lo stato del collegamento, il proprietario e la modalità (protezione) del file, potenzialmente a un costo pari al doppio degli I / O. (Potrebbe essere necessario utilizzare un'opzione come -a
o -p
on cp
per dirle di preservare gli attributi.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(suddiviso in righe separate solo per leggibilità) Ciò preserva la modalità del file (e, se sei root, il proprietario), ma lo rende di tua proprietà (se non sei root) e lo rende un nuovo, file separato.
Questo blog
(modifica "sul posto" dei file) suggerisce e spiega
{rm input_file && command …> input_file ; } < file_input
Ciò richiede che command
sia in grado di elaborare l'input standard (ma quasi tutti i filtri possono farlo). Il blog stesso lo definisce un kludge rischioso e scoraggia il suo utilizzo. E questo creerà anche un nuovo file separato (non collegato a nulla), di proprietà dell'utente e con autorizzazioni predefinite.
Il pacchetto moreutils ha un comando chiamato sponge
:
comando ... input_file | sponge the_same_file
Vedi questa risposta per maggiori informazioni.
Ecco qualcosa che mi ha sorpreso completamente:
syntaxerror dice :
[La maggior parte di queste soluzioni] fallirà su un file system di sola lettura, dove “sola lettura” significa che il tuo $HOME
sarà scrivibile, ma /tmp
sarà di sola lettura (per impostazione predefinita). Ad esempio, se hai Ubuntu e hai avviato la Console di ripristino di emergenza, questo è comunemente il caso. Inoltre, anche l'operatore del documento qui <<<
non funzionerà lì, poiché richiede /tmp
di essere letto / scritto
perché scriverà anche un file temporaneo.
(cfr. questa domanda include un strace
'd output)
In questo caso potrebbe funzionare:
Allora, qual era la domanda?
Questo è stato un argomento popolare su U&L; è affrontato nelle seguenti domande:
... e questo non conta Super User o Ask Ubuntu. Ho incorporato molte informazioni dalle risposte alle domande precedenti qui in questa risposta, ma non tutte. (Vale a dire, per ulteriori informazioni, leggi le domande sopra elencate e le loro risposte.)
PS Non ho alcuna affiliazione con il blog che ho citato, sopra.