$(<file)
(fonctionne également avec `<file`
) est un opérateur spécial du shell Korn copié par zsh
et bash
. Cela ressemble beaucoup à la substitution de commandes, mais ce n'est pas vraiment le cas.
Dans les shells POSIX, une commande simple est:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Toutes les parties sont facultatives, vous pouvez avoir des redirections uniquement, des commandes uniquement, des affectations uniquement ou des combinaisons.
S'il y a des redirections mais pas de commande, les redirections sont effectuées (donc un > file
s'ouvrirait et tronquerait file
), mais alors rien ne se passe. Donc
< file
Ouvre file
en lecture, mais rien ne se passe car il n'y a pas de commande. Donc, le file
est fermé et c'est tout. S'il $(< file)
s'agissait d'une simple substitution de commande , elle se développerait à néant.
Dans la spécification POSIX , dans $(script)
, si se script
compose uniquement de redirections, cela produit des résultats non spécifiés . C'est pour permettre ce comportement spécial du shell Korn.
Dans ksh (ici testé avec ksh93u+
), si le script se compose d'une et d'une seule commande simple (bien que les commentaires soient autorisés avant et après) qui ne se compose que de redirections (pas de commande, pas d'affectation) et si la première redirection est un stdin (fd 0) entrée uniquement ( <
, <<
ou <<<
) redirection, donc:
$(< file)
$(0< file)
$(<&3)
(également en $(0>&3)
fait car c'est en fait le même opérateur)
$(< file > foo 2> $(whatever))
mais non:
$(> foo < file)
- ni
$(0<> file)
- ni
$(< file; sleep 1)
- ni
$(< file; < file2)
puis
- tous sauf la première redirection sont ignorés (ils sont analysés)
- et il s'étend au contenu du fichier / heredoc / herestring (ou tout ce qui peut être lu à partir du descripteur de fichier si vous utilisez des choses comme
<&3
) moins les caractères de fin de ligne.
comme si, $(cat < file)
sauf que
- la lecture se fait en interne par la coque et non par
cat
- aucun tuyau ni processus supplémentaire n'est impliqué
- en conséquence de ce qui précède, puisque le code à l'intérieur n'est pas exécuté dans un sous-shell, toute modification reste par la suite (comme dans
$(<${file=foo.txt})
ou $(<file$((++n)))
)
- les erreurs de lecture (mais pas les erreurs lors de l'ouverture de fichiers ou la duplication de descripteurs de fichiers) sont silencieusement ignorées.
Dans zsh
, il est le même , sauf que ce comportement spécial est déclenché quand il ne n'y a qu'une seule redirection d'entrée de fichier ( <file
ou 0< file
, non <&3
, <<<here
, < a < b
...)
Cependant, sauf lors de l'émulation d'autres shells, dans:
< file
<&3
<<< here...
c'est quand il n'y a que des redirections d'entrée sans commandes, en dehors de la substitution de commandes, zsh
exécute le $READNULLCMD
(un pager par défaut), et quand il y a des redirections d'entrée et de sortie, le $NULLCMD
( cat
par défaut), donc même s'il $(<&3)
n'est pas reconnu comme spécial , il fonctionnera toujours comme ksh
si en appelant un pager pour le faire (ce pager agissant comme cat
puisque sa sortie standard sera un pipe).
Cependant , alors que ksh
l » $(< a < b)
élargiraient au contenu de a
, dans zsh
, il élargit le contenu de a
et b
(ou tout simplement b
si l' multios
option est désactivée), $(< a > b)
copiaient a
à b
et d' élargir à rien, etc.
bash
a un opérateur similaire mais avec quelques différences:
les commentaires sont autorisés avant mais pas après:
echo "$(
# getting the content of file
< file)"
fonctionne mais:
echo "$(< file
# getting the content of file
)"
se développe à rien.
comme dans zsh
, un seul fichier redirection stdin, bien qu'il n'y ait pas de retour à a $READNULLCMD
, alors $(<&3)
, $(< a < b)
effectuez les redirections mais ne développez rien.
- pour une raison quelconque, bien qu'il
bash
n'invoque pas cat
, il bifurque toujours un processus qui alimente le contenu du fichier via un tube, ce qui en fait beaucoup moins d'optimisation que dans d'autres shells. C'est en effet comme un $(cat < file)
où cat
serait un builtin cat
.
- en conséquence de ce qui précède, toute modification effectuée à l'intérieur est perdue par la suite (dans le
$(<${file=foo.txt})
, mentionné ci-dessus par exemple, cette $file
cession est perdue par la suite).
Dans bash
, IFS= read -rd '' var < file
(fonctionne également dans zsh
) est un moyen plus efficace de lire le contenu d'un fichier texte dans une variable. Il présente également l'avantage de conserver les caractères de nouvelle ligne de fin. Voir aussi $mapfile[file]
dans zsh
(dans le zsh/mapfile
module et uniquement pour les fichiers normaux) qui fonctionne également avec les fichiers binaires.
Notez que les variantes basées sur pdksh ksh
ont quelques variantes par rapport à ksh93. D'intérêt, dans mksh
(un de ces coquilles dérivées de pdksh), dans
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
est optimisé en ce que le contenu du document ici (sans les caractères de fin) est développé sans qu'un fichier temporaire ou un canal ne soit utilisé comme c'est le cas autrement pour les documents ici, ce qui en fait une syntaxe de citation multi-lignes efficace.
Pour être portable sur toutes les versions de ksh
, zsh
et bash
, le mieux est de se limiter à $(<file)
éviter les commentaires et en gardant à l'esprit que les modifications des variables apportées à l'intérieur peuvent ou non être conservées.
bash
interprètera cela commecat filename
", voulez-vous dire que ce comportement est spécifique à la substitution de commandes? Parce que si je cours tout< filename
seul, bash ne s'en sort pas. Il ne sortira rien et me renverra à une invite.