Come funziona `cat <> file`?


42

cat < filestampa il contenuto del file su stdout.

cat > filelegge stdin fino a quando non viene rilevato Ctrl+ De il testo di input viene scritto nel file .

cat <> file, almeno nella mia versione di Bash, stampa felicemente il contenuto del file (senza errori), ma non modifica il file né aggiorna il timestamp di modifica.

In che modo lo standard di Bash giustifica l'apparentemente ignorato >nella terza affermazione - e, cosa più importante, sta facendo qualcosa?

Risposte:


47

Bash utilizza <>per creare un descrittore di file di lettura-scrittura :

L'operatore di reindirizzamento

[n]<>word

causa l'apertura del file il cui nome è l'espansione della parola sia per la lettura che per la scrittura sul descrittore di file n o sul descrittore di file 0 se n non è specificato. Se il file non esiste, viene creato.

cat <> fileapre fileread-write e lo lega al descrittore 0 (input standard). È sostanzialmente equivalente a < filequalsiasi programma scritto in modo ragionevole, dal momento che nessuno è in grado di provare a scrivere su input standard normalmente, ma se uno lo facesse sarebbe in grado di farlo.

È possibile scrivere un semplice programma C per testare che direttamente - write(0, "hello", 6)scriverà helloin filevia standard input.

<>dovrebbe funzionare anche con qualsiasi altra shell conforme a POSIX con lo stesso effetto.


1
Scrivere ... su stdin? ... Esiste un caso d'uso valido per questo?
Qix,

3
Off-hand, non riesco a pensare a nessuno buono. Dare un descrittore esplicito ( 4<>file) è utile e suppongo che 0 sia un valore predefinito uguale a qualsiasi quando lo lasci fuori. Leggere da stdout non è migliore.
Michael Homer,

5
<>è anche utile su alcuni sistemi (come Linux) per aprire pipe denominate senza bloccare fino a quando un altro processo non lo apre per la scrittura.
Stéphane Chazelas,

1
@Qix: Beh scrivere (0, "Password:", 10) è un buon modo per richiedere una password se si intende richiedere qualcosa di simile a un tty. Sono abituato a vederlo solo su stderr ma nessuna ragione in particolare la stessa tecnica non funziona su stdin.
Giosuè,

3
@Qix - dalla logica di POSIX - L' <>operatore potrebbe essere utile per scrivere un'applicazione che ha funzionato con diversi terminali e che occasionalmente voleva avviare una shell. A sua volta quella shell non sarebbe in grado di eseguire applicazioni eseguite da un normale terminale di controllo a meno che non possa utilizzare <>... come ... il cercapersone more, che legge l'errore standard per ottenere i suoi comandi, quindi input standard e output standard sono entrambi disponibili per il loro normale utilizzo. cat food | more - >/dev/tty03 2<>/dev/tty03
Mikeserv,

38

<> fileapre il file (sul descrittore di file 0 (stdin) per impostazione predefinita, come <) in modalità lettura + scrittura senza troncamento e crea il file se non esistesse prima .

Ciò corrisponde ai O_RDWR|O_CREATflag passati alla open()chiamata di sistema. Al contrario <è O_RDONLYed >è O_WRONLY|O_CREAT|O_TRUNCe >> O_WRONLY|O_CREAT|O_APPEND.

Avere stdin scrivibile non è spesso utile poiché le applicazioni di solito non scrivono sul proprio stdin. Le applicazioni di solito non si aspettano di leggere e scrivere su un descrittore di file che ricevono all'avvio; di solito leggono da stdin (o da un descrittore di file che si aprono da soli) e scrivono su stdout o stderr (o da un descrittore di file che si aprono da soli).

<> può avere i suoi usi:

  • Si può preferire cat <> filesopra cat < filese non si desidera che il comando di fallire se filenon esiste, ma un vuoto filecreato invece.
  • L'aspetto non troncante di <>rende utile sovrascrivere i file in atto. In tal caso, tuttavia, generalmente non lo si utilizza sul descrittore di file 0:

    printf xxx 1<> file

    sostituisce i primi 3 byte di filecon xxx.

  • Su alcuni sistemi come Linux, <>su una named pipe (FIFO) apre la named pipe senza bloccare (senza attendere che un altro processo apra l'altra estremità) e garantisce che la struttura della pipe rimanga viva. Ad esempio in:

    mkfifo pipe; sed 's/foo/bar/g' <> pipe

    sedgestisce i dati in arrivo da qualsiasi numero di altri processi scrivendoli e non li vede mai eof.


1
Si noti che su AT&T ksh93, per <>impostazione predefinita è 1<>(stdout) anziché 0<>(stdin). Questo è un bug di conformità POSIX che ho segnalato e sarà risolto nella prossima versione. github.com/att/ast/issues/75 Ma fino a quando le attuali versioni di ksh93 non <>verranno utilizzate, è necessario includere il numero del descrittore di file da utilizzare in modo portabile.
Martijn Dekker,

@MartijnDekker, lo so, sono stato io a parlartene in primo luogo ;-). Nota che è solo per ksh93t + (dove il comportamento è cambiato) e versioni successive.
Stéphane Chazelas,

Quali sono (o erano) i sistemi a differenza di Linux dove mkfifo fifo; exec 3<>fifosi bloccherebbe?
Zio Billy,
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.