相似的脚本,没有sudo
,但结果相似:
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
随着bash
,脚本的其余部分则作为输入sed
,使用dash
,外壳解释它。
strace
在这些dash
脚本上运行:读取脚本块(此处为8 kB,足以容纳整个脚本),然后生成sed
:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
这意味着文件句柄位于文件末尾,并且sed
不会看到任何输入。其余部分在中缓冲dash
。(如果脚本长于8 kB的块大小,则其余部分将由读取sed
。)
另一方面,Bash返回最后一条命令的末尾:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR) = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
如果输入来自管道,则如下所示:
$ cat script.sh | bash
由于无法找到管道和承插口,因此无法进行倒带。在这种情况下,Bash会退回到一次读取一个字符来避免过度读取。(fd_to_buffered_stream()
中input.c
)做一个完整的系统调用每个字节是不是在原则上是非常有效的。实际上,与外壳大多数情况确实涉及产生整个新进程这一事实相比,我认为读取操作不会带来太大的开销。
类似的情况是这样的:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
子外壳程序必须确保read
仅读取第一行换行符,以便head
看到下一行。(这也适用dash
。)
换句话说,Bash会花更多的时间来支持为脚本本身以及从脚本执行的命令读取相同的源。dash
没有。的zsh
,并ksh93
封装在Debian中击走在这条。
sudo su
:unix.stackexchange.com/questions/218169/...