Perché il comportamento di `comando 1> file.txt 2> file.txt` è diverso da` comando 1> file.txt 2> & 1`?


20

Quando vuoi reindirizzare sia stdout che stderr sullo stesso file, puoi farlo usando command 1>file.txt 2>&1, o command &>file.txt. Ma perché il comportamento è command 1>file.txt 2>file.txtdiverso dai due comandi precedenti?

Di seguito è riportato un comando di verifica.

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

Per quanto riguarda i risultati, sembra che la seconda stringa di eco sovrascriva la prima stringa di eco quando si esegue command 1>file.txt 2>file.txt, ma non so perché lo farà. (C'è un riferimento da qualche parte?)

Risposte:


43

Devi sapere due cose:

  • Un descrittore di file aperto noto al lato della modalità applicazione di un processo fa riferimento a un oggetto kernel interno noto come descrizione del file , che è un'istanza di un file aperto. Possono esistere più descrizioni di file per file e più descrittori di file che condividono una descrizione di file.
  • La posizione corrente del file è un attributo di una descrizione del file . Pertanto, se più descrittori di file sono associati a una singola descrizione di file, condividono tutti la stessa posizione corrente del file e una modifica alla posizione del file attuata utilizzando uno di questi descrittori di file influisce su tutti gli altri descrittori di file.

    Tali modifiche sono emanate dai processi chiamando i read()/ readv(), write()/ writev(), lseek()chiamate, e di sistema simili. Il echocomando chiama write()/ writev()ovviamente.

Quindi quello che succede è questo:

  • command 1>file.txt 2>&1crea solo una descrizione del file, perché la shell apre un file solo una volta. La shell rende sia l'output standard sia i descrittori di file di errore standard associati alla descrizione di quel singolo file. Si duplica standard output su errore standard. Quindi una scrittura tramite uno dei descrittori di file sposta la posizione corrente del file condiviso: ogni scrittura va dopo la precedente la descrizione del file comune. E come puoi vedere i risultati dei echocomandi non si sovrascrivono l'un l'altro.
  • command 1>file.txt 2>file.txtcrea due descrizioni dei file, poiché la shell apre due volte lo stesso file, in risposta ai due reindirizzamenti espliciti. I descrittori di file di output standard e di errore standard vengono associati a due diverse descrizioni di file, che a loro volta vengono mappate allo stesso singolo file. Le due descrizioni dei file hanno posizioni di file correnti completamente indipendenti e ogni scrittura passa immediatamente alla scrittura precedente sulla stessa descrizione del file. E come puoi vedere il risultato è che ciò che è scritto tramite uno può sovrascrivere ciò che è scritto tramite l'altro, in vari modi in base all'ordine in cui esegui le scritture.

Ulteriori letture


1
Dovrebbe essere una descrizione file aperta anziché una descrizione file . Si tratta più del record di come il file è stato aperto più del file stesso. Questa è la terminologia utilizzata almeno dalla documentazione POSIX, Linux, Solaris e GNU.
Stéphane Chazelas

16

L'utilizzo >indica di sovrascrivere il file. Dato che stdout e stderr sono scritti nel file in due diverse operazioni, l'ultimo da scrivere sovrascriverà il primo.

Tu puoi fare:

command 1>>file.txt 2>>file.txt

o

command &>file.txt Bash v4 e versioni successive.

>> gli dice di aggiungere il file in modo che non sostituisca l'output delle operazioni precedenti.

&> è solo un modo più semplice per scrivere 2>&1


2
perché ls 1>&0e ls 0>&0mostra ancora l'output di ls?
Yvain,

Sono sorpreso che usare le >>opere. Perché questo non ha il problema di due descrizioni di file con offset indipendenti? @JdeBP, lo sai? Ho pensato che l'apertura di un file in modalità append fosse equivalente all'apertura in modalità write, cercando la posizione finale, quindi non consentendo ulteriori ricerche.
JoL

4
@jlmg: i file in modalità Append sono ricercabili, ma ogni scrittura è preceduta da una ricerca implicita fino alla fine. Se questa ricerca implicita sia atomica, mi è meno chiaro.
Kevin,

1
Ciò dipende interamente dalla domanda successiva. Quelli come questo che sono correlati indicano che la risposta è incompleta. Ed è improbabile che le persone cerchino le domande successive senza voler conoscere la risposta completa. Quindi è molto probabile che tali domande di follow-up abbiano risposte che duplicano informazioni e quindi si chiudono come duplicati.
sincero

1
@Kevin, su filesystem completamente conformi a POSIX, la ricerca implicita di O_APPEND è atomica. Detto questo, non tutti i filesystem implementano correttamente la semantica pertinente - ad esempio, NFS (almeno v3 e precedenti - non sono chiaro su v4) non ha il supporto pertinente inserito nel protocollo wire, quindi il server ha nessun modo di sapere se un client ha aperto un file con O_APPEND.
Charles Duffy,
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.