Perché shell non risolve automaticamente "l'uso inutile di cat"? [chiuso]


28

Molte persone usano oneliner e script contenenti codice lungo le linee

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Il primo catè spesso chiamato "uso inutile di gatto" perché tecnicamente richiede l'avvio di un nuovo processo (spesso /usr/bin/cat) in cui ciò potrebbe essere evitato se il comando fosse stato

< "$MYFILE" command1 | command2 > "$OUTPUT"

perché allora la shell deve solo avviarsi command1e puntare semplicemente stdinal file dato.

Perché la shell non esegue automaticamente questa conversione? Sento che la sintassi dell '"uso inutile del gatto" è più facile da leggere e la shell dovrebbe avere abbastanza informazioni per sbarazzarsi automaticamente del gatto inutile. Il file catè definito nello standard POSIX, pertanto la shell dovrebbe essere autorizzata a implementarlo internamente anziché utilizzare un percorso binario. La shell potrebbe anche contenere l'implementazione solo per una versione dell'argomento e il fallback al percorso binario.


22
Questi comandi non sono in realtà equivalenti, poiché in un caso stdin è un file e nell'altro è una pipe, quindi non sarebbe una conversione strettamente sicura. Tuttavia, potresti creare un sistema che lo ha fatto.
Michael Homer,

14
Il fatto che non si possa immaginare un caso d'uso non significa che un'applicazione non possa fare inutilmente affidamento sul comportamento specificato. Ottenere un errore lseekè un comportamento ancora definito e potrebbe causare un risultato diverso, il diverso comportamento di blocco può essere semanticamente significativo, ecc. Sarebbe possibile apportare la modifica se sapessi quali erano gli altri comandi e sapevi che non gli importava, o se non ti interessava la compatibilità a quel livello, ma il vantaggio è piuttosto piccolo. Immagino che la mancanza di benefici spinga la situazione più del costo di conformità.
Michael Homer,

3
La shell è assolutamente autorizzata a implementare catse stessa, o qualsiasi altra utility. È anche consentito sapere come funzionano le altre utility che appartengono al sistema (ad esempio, può sapere come si comporta l' grepimplementazione esterna fornita con il sistema ). Questo è completamente praticabile, quindi è del tutto giusto chiedersi perché non lo facciano.
Michael Homer,

6
@MichaelHomer, ad esempio, può sapere come si comporta l' implementazione grep esterna fornita con il sistema. Quindi la shell ora dipende dal comportamento di grep. E sed. E awk. E du. E quante centinaia se non migliaia di altre utility?
Andrew Henle,

19
Sarebbe piuttosto strano che la mia shell modifichi i miei comandi per me.
Azor Ahai,

Risposte:


25

I 2 comandi non sono equivalenti: considerare la gestione degli errori:

cat <file that doesn't exist> | less produrrà un flusso vuoto che verrà passato al programma di piping ... come tale si finisce con un display che non mostra nulla.

< <file that doesn't exist> less non riuscirà ad aprire la barra, quindi non si aprirà affatto.

Il tentativo di cambiare il primo con il secondo potrebbe interrompere qualsiasi numero di script che prevedono di eseguire il programma con un input potenzialmente vuoto.


1
Segnerò la tua risposta come accettata perché penso che questa sia la differenza più importante tra entrambe le sintassi. La variante con cateseguirà sempre il secondo comando nella pipeline mentre la variante con il solo reindirizzamento dell'input non eseguirà affatto il comando se manca il file di input.
Mikko Rantalainen,

Tuttavia, si noti che <"missing-file" grep foo | echo 2non verrà eseguito grepma verrà eseguito echo.
Mikko Rantalainen,

51

"L'uso inutile di cat" riguarda più il modo in cui scrivi il codice che ciò che viene effettivamente eseguito quando esegui lo script. È una sorta di design anti-pattern , un modo per fare qualcosa che probabilmente potrebbe essere fatto in modo più efficiente. È un errore nel comprendere come combinare al meglio gli strumenti forniti per creare un nuovo strumento. Direi che talvolta si potrebbe dire che mettere insieme più sede / o awkcomandi in una pipeline sia un sintomo di questo stesso anti-schema.

La correzione di istanze di "uso inutile di cat" in uno script è principalmente una questione di correzione manuale del codice sorgente dello script. Uno strumento come ShellCheck può essere d'aiuto sottolineando i casi ovvi:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Fare in modo che la shell esegua questa operazione automaticamente sarebbe difficile a causa della natura degli script della shell. Il modo in cui viene eseguito uno script dipende dall'ambiente ereditato dal suo processo padre e dall'implementazione specifica dei comandi esterni disponibili.

La shell non sa necessariamente cosa catsia. Potrebbe potenzialmente essere qualsiasi comando da qualsiasi parte del tuo$PATH , o una funzione.

Se fosse un comando incorporato (che potrebbe trovarsi in alcune shell), avrebbe la possibilità di riorganizzare la pipeline come sarebbe a conoscenza della semantica del suo catcomando integrato . Prima di farlo, dovrebbe inoltre fare ipotesi sul prossimo comando in cantiere, dopo l'originalecat .

Si noti che la lettura dall'input standard si comporta in modo leggermente diverso quando è collegata a una pipe e quando è connessa a un file. Una pipe non è ricercabile, quindi a seconda di ciò che fa il comando successivo nella pipeline, può o meno comportarsi diversamente se la pipeline è stata riorganizzata (può rilevare se l'input è ricercabile e decidere di fare le cose in modo diverso se lo è o se non lo è, in ogni caso si comporterebbe diversamente).

Questa domanda è simile (in senso molto generale) a " Esistono compilatori che tentano di correggere da soli gli errori di sintassi? " (Nel sito Software Engineering StackExchange), sebbene tale domanda riguardi ovviamente errori di sintassi, non schemi di progettazione inutili . L'idea di cambiare automaticamente il codice in base all'intenzione è sostanzialmente la stessa però.


È perfettamente conforme per una shell sapere cosa catsia, e gli altri comandi in corso (la regola as-if) e comportarsi di conseguenza, semplicemente non fanno qui perché è inutile e troppo difficile.
Michael Homer,

4
@MichaelHomer Sì. Ma è anche consentito di sovraccaricare un comando standard con una funzione con lo stesso nome.
Kusalananda

2
@PhilipCouling È assolutamente conforme fintanto che è noto che nessuno dei comandi della pipeline è importante. La shell è specificatamente autorizzata a sostituire le utility con builtin o funzioni shell e quelle non hanno restrizioni sull'ambiente di esecuzione, quindi finché il risultato esterno è indistinguibile è permesso. Nel tuo caso, cat /dev/ttyè quello interessante con cui sarebbe diverso <.
Michael Homer,

1
@MichaelHomer fintanto che il risultato esterno è indistinguibile è consentito Ciò significa che il comportamento dell'intero set di utilità ottimizzato in tal modo non potrà mai cambiare . Deve essere l'inferno della dipendenza suprema.
Andrew Henle,

3
@MichaelHomer Come hanno detto gli altri commenti, ovviamente è perfettamente conforme per la shell sapere che, dato l'input dell'OP, è impossibile dire cosa catfa effettivamente il comando senza eseguirlo . Per quanto ne sapete voi (e la shell), l'OP ha un comando catnel suo percorso che è una simulazione gatto interattiva, "myfile" è solo lo stato di gioco memorizzato command1e command2sta postprocedendo alcune statistiche sull'attuale sessione di gioco ...
alephzero,

34

Perché non è inutile.

Nel caso di cat file | cmd, il fd 0(stdin) di cmdsarà una pipe, e nel caso di cmd <fileesso potrebbe essere un file, un dispositivo, ecc.

Una pipe ha una semantica diversa da un file normale e la sua semantica non è un sottoinsieme di quelle di un file normale:

  • un file normale non può essere select(2)editato o modificato poll(2)in modo significativo; a select(2)su tornerà sempre "pronto". Le interfacce avanzate come epoll(2)su Linux semplicemente non funzioneranno con i file normali.

  • su Linux ci sono le chiamate di sistema ( splice(2), vmsplice(2), tee(2)), che solo di lavoro su tubi [1]

Dato che catè molto usato, potrebbe essere implementato come una shell integrata che eviterà un ulteriore processo, ma una volta iniziato su quel percorso, la stessa cosa potrebbe essere fatta con la maggior parte dei comandi: trasformare la shell in un più lento e clunkier perlo python. è probabilmente meglio scrivere un altro linguaggio di scripting con una sintassi simile a pipe per le continuazioni ;-)

[1] Se volete un semplice esempio non confezionati per l'occasione, si può guardare il mio "binario exec da stdin" git sostanza con alcune spiegazioni nel commento qui . L'implementazione catal suo interno per farlo funzionare senza UUoC lo avrebbe reso 2 o 3 volte più grande.


2
Infatti, ksh93 fa implementare alcuni comandi esterni come catinternamente.
jrw32982 supporta Monica l'

3
cat /dev/urandom | cpu_bound_programesegue le read()chiamate di sistema in un processo separato. Su Linux, ad esempio, il lavoro effettivo della CPU per generare più numeri casuali (quando il pool è vuoto) viene eseguito in quella chiamata di sistema, quindi l'utilizzo di un processo separato consente di sfruttare un core CPU separato per generare dati casuali come input. ad es. in Qual è il modo più veloce per generare un file di testo da 1 GB contenente cifre casuali?
Peter Cordes,

4
Ancora più importante per la maggior parte dei casi, significa lseekche non funzionerà. cat foo.mp4 | mpv -funzionerà, ma non puoi cercare oltre il buffer di cache di mpv o mplayer. Ma con l'input reindirizzato da un file, puoi farlo. cat | mpv -è un modo per verificare se un MP4 ha il suo moovatomo all'inizio del file, quindi può essere riprodotto senza cercare fino alla fine e viceversa (cioè se è adatto per lo streaming). È facile immaginare altri casi in cui si desidera testare un programma per file non ricercabili eseguendolo /dev/stdincon catvs. reindirizzamento.
Peter Cordes,

Questo è ancora più vero quando si utilizza xargs cat | somecmd. Se i percorsi dei file si estendono oltre il limite del buffer dei comandi, xargspossono essere eseguiti catpiù volte con conseguente flusso continuo, mentre l'utilizzo xargs somecmddiretto spesso fallisce perché somecmdnon può essere eseguito in multipli per ottenere un risultato senza interruzioni.
tasket

17

Perché rilevare un gatto inutile è davvero difficile.

Avevo una sceneggiatura di shell dove ho scritto

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

Lo script shell non è riuscito in produzione se è catstato rimosso perché è stato richiamato tramite su -c 'script.sh' someuser. Apparentemente il superfluo ha fatto catsì che il proprietario dell'input standard cambiasse all'utente che lo script era in esecuzione in modo tale da riaprirlo tramite /procfunzionante.


Questo caso sarebbe piuttosto semplice perché chiaramente non segue il modello semplice catseguito da esattamente un parametro, quindi la shell dovrebbe usare un cateseguibile reale anziché un collegamento ottimizzato. Un buon punto su possibili credenziali diverse o stdin non standard per processi reali, però.
Mikko Rantalainen,

13

tl; dr: le conchiglie non lo fanno automaticamente perché i costi superano i probabili benefici.

Altre risposte hanno sottolineato la differenza tecnica tra lo stdin che è una pipe e l'essere un file. Tenendo presente questo, la shell potrebbe fare uno dei seguenti:

  1. Implementare catcome incorporato, mantenendo comunque la distinzione tra file e pipe. Ciò consentirebbe di risparmiare il costo di un dirigente e forse, forse, un fork.
  2. Eseguire un'analisi completa della pipeline con la conoscenza dei vari comandi utilizzati per vedere se il file / pipe è importante, quindi agire in base a quello.

Successivamente devi considerare i costi e i benefici di ciascun approccio. I vantaggi sono abbastanza semplici:

  1. In entrambi i casi, evitare un exec (di cat)
  2. Nel secondo caso, quando è possibile la sostituzione del reindirizzamento, evitare un fork.
  3. Nei casi in cui è necessario utilizzare una pipe, a volte potrebbe essere possibile evitare una fork / vfork, ma spesso no. Questo perché l'equivalente del gatto deve essere eseguito contemporaneamente al resto della pipeline.

In questo modo risparmi un po 'di tempo e memoria della CPU, soprattutto se puoi evitare il fork. Naturalmente, risparmi tempo e memoria solo quando la funzione è effettivamente utilizzata. E stai davvero risparmiando il tempo fork / exec; con file più grandi, l'ora è principalmente l'ora di I / O (ad esempio, cat che legge un file dal disco). Quindi devi chiederti: quanto spesso viene catutilizzato (inutilmente) negli script di shell dove le prestazioni contano davvero? Confrontalo con altri builtin shell comuni come test- è difficile immaginare che catvenga usato (inutilmente) anche un decimo delle volte che testviene usato in luoghi che contano. Questa è un'ipotesi, non ho misurato, che è qualcosa che vorresti fare prima di qualsiasi tentativo di implementazione. (O allo stesso modo, chiedere a qualcun altro di implementare, ad esempio, una richiesta di funzionalità.)

Successivamente si chiede: quali sono i costi. I due costi che vengono in mente sono (a) codice aggiuntivo nella shell, che ne aumenta le dimensioni (e quindi eventualmente l'uso della memoria), richiede più lavori di manutenzione, è un altro punto per i bug, ecc .; e (b) sorprese di compatibilità con le versioni precedenti, POSIX catomette molte funzionalità, ad esempio core GNU GNU cat, quindi dovresti fare attenzione esattamente a cosa catimplementerebbe il builtin.

  1. L'opzione built-in aggiuntiva probabilmente non è poi così male - l'aggiunta di un altro builtin in cui esiste già un gruppo. Se avessi dati di profilazione che dimostrassero che sarebbe d'aiuto, probabilmente potresti convincere gli autori della tua shell preferita ad aggiungerli.

  2. Per quanto riguarda l'analisi della pipeline, non credo che le shell facciano qualcosa del genere attualmente (alcuni riconoscono la fine di una pipeline e possono evitare un fork). In sostanza dovresti aggiungere un ottimizzatore (primitivo) alla shell; gli ottimizzatori spesso si rivelano essere un codice complicato e la fonte di molti bug. E questi bug possono essere sorprendenti: lievi modifiche nello script della shell potrebbero finire per evitare o innescare il bug.

Postscript: puoi applicare un'analisi simile ai tuoi usi inutili di cat. Vantaggi: più facile da leggere (sebbene se command1 prenderà un file come argomento, probabilmente no). Costi: fork ed exec extra (e se command1 può prendere un file come argomento, probabilmente messaggi di errore più confusi). Se la tua analisi ti dice di usare inutilmente cat, allora vai avanti.


10

Il catcomando può accettare -come marcatore per stdin . ( POSIX , " Se un file è '-', l'utilità cat deve leggere dall'input standard in quel punto della sequenza. ") Ciò consente una semplice gestione di un file o di uno stdin laddove ciò non sia consentito.

Considera queste due banali alternative, in cui l'argomento shell $1è -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Un'altra volta catè utile in cui viene utilizzato intenzionalmente come no-op semplicemente per mantenere la sintassi della shell:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Infine, credo che l'unica volta in cui UUOC possa davvero essere richiamato correttamente sia quando catviene utilizzato con un nome file che è noto per essere un file normale (ovvero non un dispositivo o una pipe denominata) e che non viene assegnato alcun flag al comando:

cat file.txt

In qualsiasi altra situazione catpossono essere richieste le oroperties stesse.


6

Il comando cat può fare cose che la shell non può necessariamente fare (o almeno non può fare facilmente). Ad esempio, supponiamo di voler stampare caratteri che potrebbero altrimenti essere invisibili, come schede, ritorni a capo o nuove righe. * Potrebbe * esserci un modo per farlo con solo i comandi incorporati nella shell, ma non riesco a pensare a nessun altro fuori dalla mia testa. La versione GNU di cat può farlo con l' -Aargomento o gli -v -E -Targomenti (non conosco altre versioni di cat, però). Puoi anche aggiungere un prefisso a ciascuna riga con un numero di riga usando -n(di nuovo, IDK se le versioni non GNU possono farlo).

Un altro vantaggio di Cat è che può facilmente leggere più file. Per fare ciò, si può semplicemente digitare cat file1 file2 file3. Per fare lo stesso con una shell, le cose sarebbero complicate, anche se un loop attentamente realizzato potrebbe molto probabilmente ottenere lo stesso risultato. Detto questo, vuoi davvero prenderti il ​​tempo per scrivere un ciclo del genere, quando esiste un'alternativa così semplice? Io non!

La lettura dei file con cat probabilmente consumerebbe meno CPU di quella della shell, poiché cat è un programma precompilato (l'ovvia eccezione è qualsiasi shell che ha un gatto incorporato). Quando si legge un grande gruppo di file, questo potrebbe apparire evidente, ma non l'ho mai fatto sui miei computer, quindi non posso esserne sicuro.

Il comando cat può anche essere utile per forzare un comando ad accettare input standard in casi in cui potrebbe non esserlo. Considera quanto segue:

echo 8 | sleep

Il numero "8" non sarà accettato dal comando "sleep", dal momento che non è mai stato realmente concepito per accettare l'input standard. Pertanto, sleep ignorerà tale input, si lamenterà della mancanza di argomenti e uscirà. Tuttavia, se si digita:

echo 8 | sleep $(cat)

Molte shell lo espanderanno a sleep 8, e il sonno attenderà 8 secondi prima di uscire. Puoi anche fare qualcosa di simile con ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Questo comando con append file di esempio sulla macchina con l'indirizzo 1.2.3.4 con qualunque cosa sia emesso da "comando".

E questo (probabilmente) sta solo graffiando la superficie. Sono sicuro che avrei potuto trovare altri esempi di gatti utili se volevo, ma questo post è abbastanza lungo come è. Quindi, concluderò dicendo questo: chiedere alla shell di anticipare tutti questi scenari (e molti altri) non è realmente fattibile.



3

Ricorda che un utente potrebbe avere un catsuo $PATHche non è esattamente il POSIX cat(ma forse una variante che potrebbe registrare qualcosa da qualche parte). In tal caso, non si desidera che la shell lo rimuova.

La cosa PATH potrebbe cambiare in modo dinamico, e quindi cat non è quello che credi che sia. Sarebbe abbastanza difficile scrivere una shell facendo l'ottimizzazione che sogni.

Inoltre, in pratica, cat è un programma abbastanza veloce. Ci sono alcuni motivi pratici (tranne l'estetica) per evitarlo.

Vedi anche l'eccellente discorso sull'inferno di POSIX Parsing di Yann Regis-Gianas a FOSDEM2018. Fornisce altri buoni motivi per evitare di tentare di fare ciò che sogni in una shell.

Se le prestazioni fossero davvero un problema per le shell, qualcuno avrebbe proposto una shell che utilizza sofisticate ottimizzazioni del compilatore dell'intero programma, analisi statica del codice sorgente e tecniche di compilazione just-in-time (tutti e tre i domini hanno decenni di progressi e pubblicazioni scientifiche e dedicate conferenze, ad esempio nell'ambito di SIGPLAN ). Purtroppo, anche se è un argomento di ricerca interessante, che attualmente non è finanziato da agenzie di ricerca o venture capitalist, e sto deducendo che semplicemente non vale la pena. In altre parole, probabilmente non esiste un mercato significativo per l'ottimizzazione delle shell . Se hai mezzo milione di euro da spendere in tale ricerca, troverai facilmente qualcuno che lo farà e credo che darebbe risultati utili.

Da un punto di vista pratico, la riscrittura, per migliorare le sue prestazioni, viene comunemente eseguita una piccola (un centinaio di righe) di script shell in qualsiasi linguaggio di scripting migliore (Python, AWK, Guile, ...). E non è ragionevole (per molte ragioni di ingegneria del software) scrivere script di shell di grandi dimensioni: quando si scrive uno script di shell che supera un centinaio di righe, è necessario considerare di riscriverlo (anche per motivi di leggibilità e manutenzione) in un linguaggio più adatto : come linguaggio di programmazione la shell è molto scarsa. Tuttavia, ci sono molti script di shell generati di grandi dimensioni e per buoni motivi (ad esempio configurescript generati da GNU autoconf ).

Per quanto riguarda gli enormi file testuali, passarli a catcome singolo argomento non è una buona pratica, e molti amministratori di sistema sanno che (quando uno script di shell impiega più di un minuto per l'esecuzione, inizi a considerare di ottimizzarlo). Per file gigabyte di grandi dimensioni, noncat è mai lo strumento adatto per elaborarli.


3
"Abbastanza pochi motivi pratici per evitarlo" - chiunque abbia aspettato cat some-huge-log | tail -n 5di correre (dove tail -n 5 some-huge-logpotrebbe saltare dritto fino alla fine, mentre catlegge solo fronte a retro) non sarebbe d'accordo.
Charles Duffy,

Il commento verifica ^ catla creazione di un file di testo di grandi dimensioni in decine di GB (che è stato creato per il test) richiede un po 'di tempo. Non lo consiglierei.
Sergiy Kolodyazhnyy,

1
A proposito, ri: "nessun mercato significativo per l'ottimizzazione delle shell" - ksh93 è una shell di ottimizzazione, e abbastanza buona. E ' stato , per un po', ha venduto con successo come un prodotto commerciale. (Purtroppo, la licenza commerciale ha anche reso sufficientemente di nicchia che i cloni scritti male e altri successori meno capaci ma liberi dal costo hanno conquistato il mondo al di fuori di quei siti disposti a pagare per una licenza, portando alla situazione che abbiamo oggi).
Charles Duffy,

(non usando le tecniche specifiche che noti, ma francamente, quelle tecniche non hanno senso dato il modello di processo; le tecniche che applica sono, bene, ben applicate e con buoni risultati ).
Charles Duffy,

2

Aggiungendo alla risposta di @Kusalananda (e al commento di @alephzero), cat potrebbe essere qualsiasi cosa:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

o

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Non c'è motivo per cui cat (da solo) o / usr / bin / cat sul sistema sia effettivamente lo strumento concatenato.


3
Diverso dal comportamento di catè definito da POSIX e quindi non dovrebbe essere molto diverso.
roaima,

2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...sei sicuro di sapere cosa catfa adesso?
Giosuè

1
@Joshua non ha molta importanza. Sappiamo entrambi che catpuò essere ignorato, ma sappiamo anche che non dovrebbe essere sostituito inavvertitamente con qualcos'altro. Il mio commento sottolinea che POSIX impone un comportamento particolare (sottoinsieme di) che si può ragionevolmente prevedere che esista. A volte ho scritto uno script di shell che estende il comportamento di un'utilità standard. In questo caso lo script della shell ha funzionato e si è comportato proprio come lo strumento che ha sostituito, tranne per il fatto che aveva funzionalità aggiuntive.
roaima,

@Joshua: Sulla maggior parte delle piattaforme, le shell sanno (o potrebbero sapere) quali directory contengono eseguibili che implementano i comandi POSIX. Quindi potresti rimandare la sostituzione solo dopo l'espansione dell'alias e la risoluzione del percorso, e farlo solo per /bin/cat. (E lo trasformeresti in un'opzione che potresti disattivare.) O creeresti catuna shell incorporata (che forse ricade /bin/catper più argomenti?) In modo che gli utenti possano controllare se volevano o meno la versione esterna normale modo, con enable cat. Come per kill. (Stavo pensando che bash command catavrebbe funzionato, ma ciò non salta i builtin)
Peter Cordes,

Se si fornisce un alias, la shell saprà che catin quell'ambiente non fa più riferimento al solito cat. Ovviamente, l'ottimizzazione dovrebbe essere implementata dopo l'elaborazione degli alias. Considero incorporati della shell di rappresentare i comandi nella directory virtuale che è sempre anteposta al tuo percorso. Se si desidera evitare la versione integrata della shell di qualsiasi comando (ad es. test) È necessario utilizzare una variante con un percorso.
Mikko Rantalainen,

1

Due usi "inutili" per cat:

sort file.txt | cat header.txt - footer.txt | less

... qui catè usato per mescolare file e input piped.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... qui xargspuò accettare un numero praticamente infinito di nomi di file ed essere eseguito cattutte le volte che è necessario, pur facendo funzionare tutto come un flusso. Quindi questo funziona per elenchi di file di grandi dimensioni in cui l'uso diretto dixargs sort non lo fa.


Entrambi questi casi d'uso sarebbero banalmente evitati rendendo la shell integrata solo se catviene chiamata con esattamente un argomento. Soprattutto il caso in cui shviene passata una stringa e xargschiamerà catdirettamente non c'è modo in cui la shell possa usare la sua implementazione integrata.
Mikko Rantalainen,

0

A parte altre cose, cat -check aggiungerebbe ulteriori costi generali e confusione su quale utilizzo catsia effettivamente inutile, IMHO, poiché tali controlli possono essere inefficienti e creare problemi con un catutilizzo legittimo .

Quando i comandi gestiscono i flussi standard, devono solo preoccuparsi di leggere / scrivere nei descrittori di file standard. I comandi possono sapere se lo stdin è ricercabile / cercabile o meno, il che indica una pipe o un file.

Se aggiungiamo al mix controllando quale processo fornisce effettivamente quel contenuto di stdin, dovremo trovare il processo dall'altra parte della pipe e applicare l'ottimizzazione appropriata. Questo può essere fatto in termini di shell stessa, come mostrato nel post SuperUser di Kyle Jones, e in termini di shell che è

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

come mostrato nel post collegato. Sono altri 3 comandi (quindi extrafork() s exec()) e traversate ricorsive (così tante readdir()chiamate).

In termini di codice sorgente C e shell, la shell conosce già il processo figlio, quindi non c'è bisogno di ricorsione, ma come facciamo a sapere quando ottimizzare e quando catè effettivamente inutile? Esistono infatti utili usi di cat , come ad esempio

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Sarebbe probabilmente uno spreco e un sovraccarico inutile aggiungere tale ottimizzazione alla shell. Come già menzionato nella risposta di Kusalanda, UUOC riguarda maggiormente la mancanza di comprensione da parte dell'utente di come combinare meglio i comandi per ottenere i migliori risultati.

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.