Comando per l'output del contenuto del file su stdout?


28

So che catpuò farlo, ma il suo scopo principale è concatenare piuttosto che semplicemente visualizzare il contenuto.

So anche di lesse more, ma sto cercando qualcosa di semplice ( non un cercapersone ) che metta semplicemente in uscita il contenuto di un file sul terminale ed è creato appositamente per questo, se esiste.


1
In realtà il 99% delle volte che usi cat è quello di visualizzare i file piuttosto che concatenare qualsiasi cosa.
LatinSuD,

1
@LatinSuD - il 100% delle volte - catconcatena.
Mikeserv,

@mikeserv: è una questione di cosa intendi eseguendo un'operazione; il normale utilizzo del linguaggio significherebbe che viene eseguito almeno una volta. La "stampa" di una stringa vuota non implica la stampa di alcun carattere; sarebbe giusto dire che non sta stampando nulla. Ora il computing a+b+ccomporta l'esecuzione di 2 aggiunte e il calcolo anon comporta l'aggiunta di nulla. Allo stesso modo, l'esecuzione cat fnon implica la concatenazione di nulla (anche se questa è l'unica cosa che "concatenare una sequenza di un file" potrebbe significare).
Marc van Leeuwen,

2
@mikeserv: non capisco cosa intendi con + out. Sicuramente catlegge un file e scrive un altro file (stream), ma ciò non significa che concatena qualcosa. Se forse vuoi dire che cat fsta effettivamente facendo cat - f, non è vero.
Marc van Leeuwen,

1
@ confused00: catdoveva davvero concatenare ( cat file1 file2concatenerà entrambi i file su stdout). Ma il suo effetto collaterale è che, quando si ha solo 1 file come argomento, invia quel file a stdout (ovunque vada, o il proprio terminale, o reindirizzato a qualcosa). Quindi non è stato creato nessun altro comando solo per l'output su stdout, come catesisteva e lo permetteva semplicemente. Pertanto si desidera utilizzare cat.
Olivier Dulac il

Risposte:


37

Il più ovvio è cat. Ma dai anche un'occhiata a heade tail. Ci sono anche altri utillities shell per stampare un file riga per riga: sed, awk, grep. Ma quelli sono per alternare il contenuto del file o per cercare all'interno del file.

Ho fatto alcuni test per stimare quale sia il più efficace. Corro tutto attraverso straceper vedere quale ha effettuato il minor numero di chiamate di sistema. Il mio file ha 1275 righe.

  • awk: 1355 chiamate di sistema
  • cat: 51 chiamate di sistema
  • grep: 1337 chiamate di sistema
  • head: 93 chiamate di sistema
  • tail: 130 chiamate di sistema
  • sed: 1378 chiamate di sistema

Come puoi vedere, anche se è catstato progettato per concatenare i file, è il più veloce ed efficace. sed, awkE grepstampato il file riga per riga, che il motivo per cui essi hanno più che 1275 chiamate di sistema.


8
Buona idea per contare i syscalls!
Jan

1
+1, la risposta è più accurata (sul significato di gatto), più completa (alternative) e studiata (syscalls)
Olivier Dulac

23

So che catpuò farlo, ma il suo scopo principale è concatenare piuttosto che semplicemente visualizzare il contenuto.

Lo scopo catè esattamente quello, leggere un file e inviarlo a stdout.


1
Ma cat --helpdice "Concatena FILE (s), o input standard, a output standard". Non voglio concatenate nulla
confused00

18
Che ci crediate o no, il gatto è esattamente quello che stai cercando comunque.
Jan

5
No, @ confused00, Jan ha ragione. Il fatto è - il terminale è stdout - vedi? fare readlink /dev/fd/1ad esempio - dovresti inserire il nome del tuo tty lì se eseguito a un prompt standard. Quindi concatenare l'input all'output è ciò che stai chiedendo di fare.
Mikeserv,

2
@mikeserv Sì, vedo il tuo punto, immagino di essere stato troppo fissato sul significato di "concatenare".
confused00

3
La logica è che stampare il contenuto di un file è solo un caso speciale di stampa in sequenza del contenuto di uno o più file.
zwol,

10

Innanzitutto, catscrive nell'output standard, che non è necessariamente un terminale, anche se è catstato digitato come parte di un comando in una shell interattiva. Se hai davvero bisogno di qualcosa da scrivere sul terminale anche quando viene reindirizzato l'output standard, non è così facile (devi specificare quale terminale, e potrebbe non essercene nemmeno uno se il comando viene eseguito da uno script), sebbene uno potrebbe (ab) utilizzare l'output di errore standard se il comando fa semplicemente parte di una pipeline. Ma dal momento che hai indicato che cateffettivamente fa il lavoro, suppongo che non ti stia chiedendo una situazione del genere.

Se il tuo scopo fosse quello di inviare ciò che è scritto nell'output standard in una pipeline, l'utilizzo catsarebbe idoneo al Premio Inutile Uso del Gatto , poiché cat file | pipeline(dove pipelinesta per qualsiasi pipeline) può essere fatto in modo più efficiente <file pipeline. Ma ancora una volta, dalle tue parole deduco che questa non era la tua intenzione.

Quindi non è così chiaro di cosa ti preoccupi. Se trovi cattroppo tempo per scrivere, puoi definire un alias a uno o due caratteri (ci sono ancora alcuni di questi nomi che rimangono inutilizzati in Unix standard). Se comunque ti preoccupi che catpassi cicli inutili, non dovresti.

Se esistesse un programma nullche non accetta argomenti e copia semplicemente l'input standard nell'output standard (l'oggetto neutro per le pipeline), è possibile fare ciò che si desidera <file null. Non esiste un programma del genere, anche se sarebbe facile scrivere (un programma C con una sola riga mainpuò fare il lavoro), ma chiamare catsenza argomenti (o cat -se ti piace essere esplicito) fa proprio questo.

Se esistesse un nocatprogramma che accetta esattamente un argomento per il nome del file, prova ad aprire il file, se non è in grado di lamentarsi, e in caso contrario procede alla copia dal file nell'output standard, sarebbe proprio quello che stai chiedendo. È solo leggermente più difficile da scrivere rispetto al fatto che nullil lavoro principale consiste nell'aprire il file, testare e possibilmente lamentarsi (se sei meticoloso, potresti anche voler includere un test che ci sia esattamente un argomento e lamentarti diversamente). Ma di nuovo cat, ora fornito con un singolo argomento, fa proprio questo, quindi non c'è bisogno di alcun nocatprogramma.

Una volta che sei riuscito a scrivere il nocatprogramma, perché fermarsi a un singolo argomento? Avvolgere il codice in un ciclo non for(;*argp!=NULL;++argp)è affatto uno sforzo, aggiunge al massimo un paio di istruzioni macchina al binario ed evita di dover lamentare un numero errato di argomenti (che risparmia molte più istruzioni). Voilà una versione primitiva di cat, concatenare file. (Ad essere sincero devi modificarlo un po 'in modo che senza argomenti si comporti come null.)

Naturalmente nel vero catprogramma hanno aggiunto alcune campane e fischietti, perché lo fanno sempre. Ma l'essenza è che l'aspetto di "concatenazione" dei catcosti non comporta alcuno sforzo, né per il programmatore né per la macchina che lo esegue. Il fatto che catsussume nulle nocatspiega la non esistenza di tali programmi. Evita di utilizzare catcon un singolo argomento se il risultato entra in una pipeline, ma se viene utilizzato solo per visualizzare il contenuto del file sul terminale, anche la pagina a cui ho collegato ammette che questo è un uso utile di cat, quindi non esitare.


Puoi verificare che catsia realmente implementato da un semplice ciclo attorno a una nocatfunzionalità ipotetica , chiamando catcon diversi nomi di file tra cui un nome non valido, non in prima posizione: piuttosto che lamentarti subito che questo file non esiste, catprima scarica il precedente file validi, quindi si lamenta del file non valido (almeno così si comporta il mio gatto).


7

Sotto zshprova

<file

Credo che sia il modo più breve per stampare un file. Usa 'nascosto' cat(o morese stdout è un terminale), ma il comando usato per la stampa è controllato da una READNULLCMDvariabile che puoi tranquillamente sovrascrivere direttamente dal nome del comando o anche da qualche funzione. Ad esempio per stampare file con numerazione delle righe:

numcat() { nl -s'> ' -w2 - }
READNULLCMD=numcat
<file

5

POSIX definisce cat come:

NOME

cat - concatena e stampa i file

SINOSSI

cat [-u] [file ...]

DESCRIZIONE

L'utilità cat deve leggere i file in sequenza e deve scrivere i loro contenuti sullo standard output nella stessa sequenza.

Quindi penso che concatenare qui significhi leggere i file in sequenza .


5

So che questa è una domanda passata. Tecnicamente, poiché la stampa del contenuto di un file stdoutè una forma di concatenazione, catè semanticamente appropriata. Non dimenticare che printfè semanticamente destinato a formattare e stampare i dati. Bash fornisce anche la sintassi per reindirizzare l'input e l'output dai file. Una combinazione di questi potrebbe produrre questo:

printf '%s' "$(<file.txt)"

4
Oltre ad essere particolarmente rotonda, il comando visualizzato non è equivalente a cat file.txt, poiché rimuoverà tutte le nuove righe finali (lo $(...)fa).
Marc van Leeuwen,

+1, bella cattura. Non lo sapevo.
James M. Lay

3

Uso dei bashbuiltin ed evitando la creazione di sottoprocessi:

{ while IFS='' read -rd '' _bcat_; do printf '%s\0' "${_bcat_}"; done; printf '%s' "${_bcat_}"; unset _bcat_; } <'/path/to/file'

IFSverrà applicato solo ai readcomandi, quindi non preoccuparti dei IFScambiamenti globali .

Loop richiesto per gestire i caratteri null (grazie a Stéphane Chazelas).

In questo modo non è adatto per file di grandi dimensioni perché il contenuto del file viene letto prima nella variabile (quindi nella memoria). A proposito, ho provato a stampare file di testo 39M in questo modo e l'utilizzo della memoria bash non ha superato 5M, quindi non sono sicuro di questo caso.

Dannatamente lento e CPU inefficiente: per lo stesso file 39M ci sono voluti circa 3 minuti con un utilizzo del 100% del single core.

Per file di grandi dimensioni o binari è meglio usare cat '/path/to/file'o anche dd if='/path/to/file' bs=1Mse possibile.


1
Vedi anche pv -qquali su Linux possono usare splice()quali per alcuni tipi di stdin / stdout miglioreranno le prestazioni.
Stéphane Chazelas,

1

Proprio come una dimostrazione, puoi farlo

cp foo /dev/stdout
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.