$(<file)
(funziona anche con `<file`
) è un operatore speciale della shell Korn copiata da zsh
e bash
. Assomiglia molto alla sostituzione dei comandi, ma in realtà non lo è.
Nelle shell POSIX, un semplice comando è:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Tutte le parti sono opzionali, puoi avere solo reindirizzamenti, solo comandi, solo assegnazioni o combinazioni.
Se ci sono reindirizzamenti ma nessun comando, i reindirizzamenti vengono eseguiti (quindi > file
verrebbe aperto e troncato file
), ma poi non accade nulla. Così
< file
Si apre file
per la lettura, ma poi non succede nulla in quanto non vi è alcun comando. Quindi file
viene chiuso e basta. Se $(< file)
fosse una semplice sostituzione di comando , non si espanderebbe a nulla.
Nella specifica POSIX , in $(script)
, se è script
costituito solo da reindirizzamenti, produce risultati non specificati . Questo per consentire quel comportamento speciale della shell Korn.
In ksh (qui testato con ksh93u+
), se lo script è costituito da un solo e semplice comando (sebbene i commenti siano consentiti prima e dopo) che consiste solo di reindirizzamenti (nessun comando, nessuna assegnazione) e se il primo reindirizzamento è uno stdin (fd 0) inserisci solo ( <
, <<
o <<<
) reindirizzamento, quindi:
$(< file)
$(0< file)
$(<&3)
(anche in $(0>&3)
realtà poiché è in effetti lo stesso operatore)
$(< file > foo 2> $(whatever))
ma no:
$(> foo < file)
- né
$(0<> file)
- né
$(< file; sleep 1)
- né
$(< file; < file2)
poi
- tutti tranne il primo reindirizzamento vengono ignorati (vengono analizzati)
- e si espande nel contenuto del file / heredoc / herestring (o qualsiasi cosa possa essere letta dal descrittore di file se si usano cose del genere
<&3
) meno i caratteri di nuova riga finali.
come se usando $(cat < file)
tranne quello
- la lettura viene eseguita internamente dalla shell e non da
cat
- nessuna pipa né processo extra è coinvolto
- come conseguenza di quanto sopra, dato che il codice interno non viene eseguito in una subshell, qualsiasi modifica rimane in seguito (come in
$(<${file=foo.txt})
o $(<file$((++n)))
)
- errori di lettura (sebbene non errori durante l'apertura di file o la duplicazione di descrittori di file) vengono silenziosamente ignorati.
In zsh
, è lo stesso, tranne che quel comportamento speciale viene attivato solo quando c'è solo una redirezione di input del file ( <file
o 0< file
, no <&3
, <<<here
, < a < b
...)
Tuttavia, tranne quando si emulano altre shell, in
< file
<&3
<<< here...
cioè quando ci sono solo reindirizzamenti di input senza comandi, al di fuori della sostituzione dei comandi, zsh
viene eseguito $READNULLCMD
(un pager per impostazione predefinita) e quando ci sono sia reindirizzamenti di input e output, il $NULLCMD
( cat
di default), quindi anche se $(<&3)
non viene riconosciuto come speciale operatore, funzionerà comunque come ksh
se invocando un cercapersone per farlo (quel cercapersone si comporta come cat
poiché il suo stdout sarà una pipe).
Tuttavia, mentre ksh
's $(< a < b)
sarebbe espandersi per il contenuto di a
, a zsh
, si espande per il contenuto di a
e b
(o solo b
se l' multios
opzione è disabilitata), $(< a > b)
si copia a
a b
ed espandere a nulla, etc.
bash
ha un operatore simile ma con alcune differenze:
i commenti sono consentiti prima ma non dopo:
echo "$(
# getting the content of file
< file)"
funziona ma:
echo "$(< file
# getting the content of file
)"
non si espande nel nulla.
come in zsh
, solo un reindirizzamento stdin del file, anche se non è possibile ricorrere a un $READNULLCMD
, quindi $(<&3)
, $(< a < b)
esegui i reindirizzamenti ma espandi a nulla.
- per qualche motivo, sebbene
bash
non invochi cat
, bifora comunque un processo che alimenta il contenuto del file attraverso una pipe rendendolo molto meno ottimizzato rispetto ad altre shell. In effetti è come un punto in $(cat < file)
cui cat
sarebbe incorporato cat
.
- come conseguenza di quanto sopra, qualsiasi modifica apportata all'interno viene persa in seguito (
$(<${file=foo.txt})
ad esempio, sopra citato, tale $file
incarico viene perso in seguito).
In bash
, IFS= read -rd '' var < file
(funziona anche in zsh
) è un modo più efficace per leggere il contenuto di un file di testo in una variabile. Ha anche il vantaggio di preservare i nuovi caratteri finali. Vedi anche $mapfile[file]
in zsh
(nel zsh/mapfile
modulo e solo per file normali) che funziona anche con file binari.
Si noti che le varianti basate su pdksh ksh
hanno alcune varianti rispetto a ksh93. Di interesse, in mksh
(una di quelle conchiglie derivate da pdksh), in
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
è ottimizzato in quanto il contenuto del documento Here (senza i caratteri finali) viene espanso senza l'utilizzo di un file o di una pipe temporanea, come altrimenti accade per i documenti qui, il che lo rende un'efficace sintassi di quotazione su più righe.
Essere portabili su tutte le versioni di ksh
, zsh
e bash
, il migliore è limitarsi a $(<file)
evitare solo commenti e tenendo presente che le modifiche alle variabili apportate all'interno possono o meno essere preservate.
bash
lo interpreterai comecat filename
", intendi questo comportamento specifico per la sostituzione dei comandi? Perché se corro< filename
da solo, bash non lo catapulta. Non emetterà nulla e tornerà a un prompt.