Bash中$(< file)与IFS='' read -r -d '' VAR < file的差异及使用疑问
Bash中$(< file)与IFS='' read -r -d '' VAR < file的差异及使用疑问
嘿,这个问题问到点子上了!咱这些天天跟Bash脚本打交道的人,对这俩写法的坑和优势门儿清,来给你唠唠明白:
一、核心功能与适用场景的本质区别
- 先说
$(< file):这其实是Bash给咱们的一个小优化,本质属于命令替换。它会把整个文件的内容读出来,然后直接输出到当前Shell的上下文里。你可以把它当“文件内容的直接占位符”用,比如赋值给变量(但必须加双引号),或者直接传给其他命令当参数。 - 再看
IFS='' read -r -d '' VAR < file:这是用Shell内置的read命令做完全定向的变量赋值。-d ''是告诉read“读到空字符才停”(普通文本文件里基本没这玩意儿,所以等价于读到文件结尾),IFS=''是禁止read偷偷吃掉开头结尾的空白(包括换行),-r是不让反斜杠搞转义的鬼。它的目标很明确:把文件内容原封不动塞进变量VAR里。
二、特殊字符与“副作用”的天差地别
这部分是最容易踩坑的,必须掰扯细:
$(< file)的坑点:- 如果你忘了给它套双引号,那麻烦大了:文件里的空格、制表符、换行全都会被Shell当成“分词符”,把内容拆得稀碎;要是文件里有
*``?这类通配符,Shell还会把它展开成当前目录的文件列表,完全偏离你要读文件的初衷! - 就算加了双引号,它还有个隐蔽的问题:会吃掉文件最后一行的换行符。这是命令替换的天生规则——不管你读的内容最后有没有换行,命令替换都会把末尾的换行给砍掉。
- 如果你忘了给它套双引号,那麻烦大了:文件里的空格、制表符、换行全都会被Shell当成“分词符”,把内容拆得稀碎;要是文件里有
read写法的安全性:- 只要你写对了
IFS='' read -r -d '',那文件里的所有内容(开头结尾的空格、所有换行、反斜杠)都会原封不动存到变量里,不会有分词、glob展开的问题,也不会吃掉最后一个换行。 - 唯一的小限制:如果文件里包含空字符(
\0,一般只有二进制文件才会有),read会在第一个空字符的位置停下来,没法读后面的内容。但普通文本场景下根本遇不到这情况。
- 只要你写对了
三、性能差异:基本可以忽略
俩写法都是Bash的内置实现,都不用启动额外的子进程(不像cat file还要开个cat进程),所以性能上几乎没差别。哪怕是读几百MB的大文件,两者的速度也差不了多少——真要读超大文件的话,其实不管哪种写法都不推荐把整个文件塞进内存,那时候你该用逐行处理的方式了。
四、为啥Bash脚本里很少见$(< file)?
这也是很多人疑惑的点,明明它写法更短,为啥大家宁愿写长的read?主要有这几个原因:
- 坑太多,容错率低:新手很容易忘了加双引号,一不留神就触发分词或glob展开,排查起来贼麻烦。而read的写法只要你一次写对,就不会踩这些坑,属于“写一次放心用”的类型。
- 语义更清晰:别人看你的脚本,看到
IFS='' read -r -d '' VAR < file,一眼就懂“哦,这是把整个文件内容原封不动存到VAR里”;但看到$(< file),还得看你有没有加引号、后面接了啥,才能猜你的意图,维护起来成本高。 - 灵活性更强:read的写法可以灵活调整,比如你只想读第一行,去掉
-d ''就行;想读前N个字符,加-n N选项。而$(< file)只能读整个文件,没法做局部读取,要改的话还得结合其他命令,反而麻烦。
内容来源于stack exchange




