$(<file)(也适用于`<file`)是由zsh和复制的Korn shell的特殊运算符bash。它看起来确实很像命令替换,但实际上并非如此。
在POSIX shell中,一个简单的命令是:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
所有部分都是可选的,您只能进行重定向,仅进行命令,仅进行分配或组合。
如果存在重定向但没有命令,则会执行重定向(因此a > file将打开并截断file),但是什么也没有发生。所以
< file
打开file以供阅读,但是由于没有命令,因此什么也没有发生。因此,file将其关闭,仅此而已。如果$(< file)是简单的命令替换,则它将扩展为空。
在POSIX规范中$(script),如果script仅包含重定向,则会产生未指定的结果。这是为了让Korn shell具有特殊的行为。
在ksh(此处已通过进行测试ksh93u+)中,如果脚本仅包含一个且仅包含重定向(无命令,无赋值)的简单命令(尽管前后允许使用注释),并且第一个重定向为stdin(fd 0)仅输入(<,<<或<<<)重定向,因此:
$(< file)
$(0< file)
$(<&3)($(0>&3)实际上也是因为实际上是同一运算符)
$(< file > foo 2> $(whatever))
但不是:
$(> foo < file)
- 也不
$(0<> file)
- 也不
$(< file; sleep 1)
- 也不
$(< file; < file2)
然后
- 除了第一个重定向之外的所有内容都将被忽略(将它们解析掉)
- 并扩展为文件/ heredoc / herestring的内容(如果使用诸如之类的东西,也可以从文件描述符中读取任何内容
<&3)减去结尾的换行符。
像使用$(cat < file)不同之处在于
- 读取是通过外壳而不是内部完成的
cat
- 没有管道也没有额外的过程
- 由于上述原因,由于内部代码未在子shell中运行,因此此后仍保留任何修改(如
$(<${file=foo.txt})或$(<file$((++n))))
- 读错误(尽管在打开文件或复制文件描述符时不会出错)将被静默忽略。
在zsh,它的不同之处在于,当只有一个文件输入重定向特殊行为时,才会触发相同(<file或0< file没有<&3,<<<here,< a < b...)
但是,除了模拟其他shell以外,在:
< file
<&3
<<< here...
也就是说,只有输入重定向而不执行命令时,在命令替换之外zsh运行$READNULLCMD(默认为寻呼机),并且当同时存在输入和输出重定向时,$NULLCMD(cat默认为),即使$(<&3)没有被识别为特殊运算符,它仍然可以像ksh通过调用分页器执行操作一样工作(该分页器的行为类似,cat因为其标准输出将是管道)。
但是同时ksh的$(< a < b)将扩大到的内容a,在zsh,它扩展到的内容a和b(或只是b如果multios选项被禁用),$(< a > b)将复制a到b并扩大到什么,等等。
bash 具有相似的运算符,但有一些区别:
允许在注释之前但之后不允许注释:
echo "$(
# getting the content of file
< file)"
可以,但是:
echo "$(< file
# getting the content of file
)"
扩展为空。
像in中一样zsh,只有一个文件stdin重定向,尽管没有回退到a $READNULLCMD,所以$(<&3),$(< a < b)请执行重定向,但扩展到无。
- 由于某些原因,尽管
bash不调用cat,它仍然派生出一个通过管道来馈送文件内容的进程,这使其优化程度远低于其他Shell。它像一个作用$(cat < file)在那里cat将是一个内置cat。
- 由于上述原因,之后所做的任何更改都将丢失(
$(<${file=foo.txt})例如,在上述的中,此$file分配随后将丢失)。
在中bash,IFS= read -rd '' var < file (也可以在中使用zsh)是一种将文本文件的内容读入变量的更有效的方法。它还具有保留尾随换行符的好处。另请参阅$mapfile[file]中的内容zsh(在zsh/mapfile模块中,仅适用于常规文件),该内容也适用于二进制文件。
请注意,ksh与ksh93相比,基于pdksh的变体有一些变体。有趣的是,mksh(这些pdksh衍生的外壳之一)
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
通过在不使用临时文件或管道的情况下扩展here文档的内容(不带结尾字符)的方式优化了here文档的内容,这与here document的情况不同,这使其成为有效的多行引用语法。
可以移植到所有版本ksh,zsh并且bash,最好是限制只能$(<file)避免意见,并铭记修改变量内可能会或可能不会被保留做。
bash将解释为cat filename”时,是否表示此行为特定于命令替换?因为如果我自己运行< filename,bash不会解决问题。它不会输出任何内容,并让我返回提示。