$(<file)(funziona anche con `<file`) è un operatore speciale della shell Korn copiata da zshe 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 > fileverrebbe aperto e troncato file), ma poi non accade nulla. Così
< file
Si apre fileper la lettura, ma poi non succede nulla in quanto non vi è alcun comando. Quindi fileviene chiuso e basta. Se $(< file)fosse una semplice sostituzione di comando , non si espanderebbe a nulla.
Nella specifica POSIX , in $(script), se è scriptcostituito 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 ( <fileo 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, zshviene eseguito $READNULLCMD(un pager per impostazione predefinita) e quando ci sono sia reindirizzamenti di input e output, il $NULLCMD( catdi default), quindi anche se $(<&3)non viene riconosciuto come speciale operatore, funzionerà comunque come kshse invocando un cercapersone per farlo (quel cercapersone si comporta come catpoiché 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 ae b(o solo bse l' multiosopzione è disabilitata), $(< a > b)si copia aa bed 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
bashnon 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 catsarebbe incorporato cat.
- come conseguenza di quanto sopra, qualsiasi modifica apportata all'interno viene persa in seguito (
$(<${file=foo.txt})ad esempio, sopra citato, tale $fileincarico 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/mapfilemodulo e solo per file normali) che funziona anche con file binari.
Si noti che le varianti basate su pdksh kshhanno 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, zshe 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.
bashlo interpreterai comecat filename", intendi questo comportamento specifico per la sostituzione dei comandi? Perché se corro< filenameda solo, bash non lo catapulta. Non emetterà nulla e tornerà a un prompt.