我的朋友问我为什么这两个简单的脚本在两个 shell 中都不起作用:
测试文件“abc.txt”:
aaa
111
bbb
111
ccc
111
ddd
脚本#1(a):
#!/bin/sh
while read -r line ; do
echo "Processing $line"
done < <(grep 111 abc.txt)
输出:
./a: line 4: syntax error near unexpected token `<'
./a: line 4: `done < <(grep 111 abc.txt)'
脚本#2(b):
#!/bin/bash
while read -r line ; do
echo "Processing $line"
done < <(grep 111 abc.txt)
输出:
Processing 111
Processing 111
Processing 111
我检查了我的计算机上的 bash 和 sh,如果我理解正确的话,那么这就是同一件事。
/bin/sh 仅仅是 /bin/bash 的一个链接:
-rwxr-xr-x 1 root root 938736 May 10 2012 bash
lrwxrwxrwx. 1 root root 4 Feb 13 10:20 sh -> bash
有人能解释一下区别在哪里吗?
答案1
这是因为 Bash 在 时$0
的行为有所不同sh
。
从Bash 的行为 [Bash Hackers Wiki]:
SH 模式
当 Bash 以 SH 兼容模式启动时,它会尝试尽可能地模仿历史版本的启动行为
sh
,同时符合 POSIX® 标准。如果是登录 shell,则读取的配置文件为/etc/profile
和 。~/.profile
如果它不是登录 shell,则会评估环境变量 ENV,并将生成的文件名作为启动文件的名称。
读取启动文件后,Bash 进入POSIX(r) 兼容模式(用于运行,而不是用于启动!)。
在以下情况下,Bash 会以
sh
兼容模式启动:
- 中的基本文件名
argv[0]
是sh
(请注意,聪明的 Linux 用户.../bin/sh
可能链接到/bin/bash
,但这并不意味着它的作用类似于/bin/bash
)
更多信息请访问Bash 参考手册:Bash POSIX 模式, 具体来说:
- 无法进行进程替换。
这就是您的sh
脚本失败的原因,因为<(..)
语法使用了进程替换。
答案2
根据
man bash
它说
When invoked as sh, bash enters posix mode after the startup files are read.
因此,在使用 运行脚本时,您无法使用 bash 功能/bin/sh
。