Perché la sostituzione del processo BASH non funziona con alcuni comandi?


29

A volte la sostituzione del processo non funzionerà come previsto. Ecco un esempio:

Ingresso:

gcc <(echo 'int main(){return 0;}')

Produzione:

/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status

Ingresso:

Ma funziona come previsto se utilizzato con un comando diverso:

grep main <(echo 'int main(){return 0;}')

Produzione:

int main(){return 0;}

Ho notato simili errori con altri comandi (cioè il comando che si aspetta il file dalla sostituzione del processo non può usare /dev/fd/63o simile). Questo fallimento con gccè solo il più recente. Esiste una regola generale di cui dovrei essere consapevole per determinare quando la sostituzione del processo fallirà in questo modo e non dovrebbe essere utilizzata?

Sto usando questa versione BASH su Ubuntu 12.04 (l'ho visto anche in arch e debian):
GNU bash, versione 4.3.11 (1) -release (i686-pc-linux-gnu)


1
illegal seeksembra la risposta - quello |pipeche bashpunta al programma eseguito non è un file ricercabile. probabilmente se non riesci con successo echo data | command /dev/fd/0a un programma, avrai una fortuna simile con <(cmd). Non fornisce un file su disco - sostituisce solo un argomento che punta a un descrittore di file di pipe.
Mikeserv,

2
In questo caso particolare, sebbene gcc possa accettare l'input standard, (per impostazione predefinita) usa l'estensione del nome del file per determinare la lingua. Quindi prova gcc -xc <(echo 'int main(){return 0;}')(che imposta Cesplicitamente la lingua ).
Steeldriver,

Sono stato diretto qui in risposta alla mia domanda, che sembra essere probabilmente un altro esempio di questo. superuser.com/questions/1243405 . Grazie per aver formulato la domanda meglio di me.
Jonathan Hartley,

Risposte:


33

La sostituzione del processo si traduce in un file speciale (come /dev/fd/63nell'esempio) che si comporta come l'estremità di lettura di una pipe denominata. Questo file può essere aperto e letto, ma non scritto, non cercato.

I comandi che trattano i loro argomenti come flussi puri funzionano mentre i comandi che si aspettano di cercare nei file loro assegnati (o di scrivere su di essi) non funzioneranno. Il tipo di comando che opera volontà è ciò che è di solito considerato un filtro: cat, grep, sed, gzip, awk, ecc ... Un esempio di un comando che non funziona è un editor come vio di un'operazione di file come mv.

gccvuole essere in grado di eseguire un accesso casuale sui suoi file di input per rilevare in quale lingua sono scritti. Se invece dai gccun suggerimento sulla lingua del file di input, è felice di eseguire lo streaming del file:

gcc -x c <(echo 'int main(){return 0;}')

La forma più semplice e diretta senza sostituzione del processo funziona anche:

echo 'int main(){return 0;}' | gcc -x c -

Si noti che questo non è specifico per bash. Tutte le shell che supportano la sostituzione dei processi si comportano allo stesso modo.


+1 per la soluzione alternativa di gcc ma non sono sicuro del tuo punto riguardo ai file. Il <()formato dovrebbe agire come un file a tutti gli effetti. In realtà, non conosco alcun comando che preveda un file che non sarà soddisfatto <(). Quelli che non funzionano sono quelli che si aspettano nomi di file , non file. Ad esempio, si grep -faspetta un file e funziona bene con <().
terdon

4
@terndon Di sicuro <()produce un nome di file (il costrutto si espande /proc/self/fd/somethingsul mio sistema). Questo nome, quando aperto, si comporta come la fine letta di una named pipe ( S_IFIFO) piuttosto che di un normale file ( S_IFREG) in quanto è support read()e altri ma non seek().
Celada,

7
Si noti che zshsupporta una terza forma di sostituzione del processo che utilizza file temporanei appositamente per questo scopo:gcc =(echo 'int main(){return 0;}')
Stéphane Chazelas,

forse in relazione , ma funziona con <(echo '...')ma non con <(git show ...). qualche idea sul perché potrebbe essere?
Jörn Hees,

2
GCC non "esegue l'accesso casuale sui suoi file di input per rilevare in quale lingua sono scritti." Guarda solo l'estensione del nome file. Se il nome file non ha estensione (o se ne ha una non riconosciuta), GCC presume che il file sia un file oggetto o uno script linker e lo passi a ld(che rileva i formati oggetto). -xnon è un suggerimento; è una dichiarazione. Se si specifica -x f95, GCC passerà il file al compilatore Fortran-95 indipendentemente dal nome o dal contenuto. Vedi gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Overall-Options.html
rici,
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.