2

SUSv4 2016版中sh的STDIN的描述说

它不应以这样一种方式进行预读,即被调用的命令打算读取的任何字符都被 shell 消耗

我做了一个实验,通过将以下脚本文件重定向到sh -s

#!/bin/sh
./rewind # a c program that reads up its stdin, prints it to stdout, before SEEK_SET its standard input to 0. 
echo 1234-1234

它不断打印出“echo 1234-1234”。(如果 shell 消耗了整个文件块,它只会打印出“1234-1234”)

很明显,shell(至少是我的)确实在行边界处读取。

但是,当我检查 FreeBSD ash "input.c" 源代码时,它读取的是 BUFSIZ 字节块,我不明白它是如何保留行边界的。

我想知道的是:当它们的源代码明显显示它们以块的形式读取时,shell 如何保留行边界?

4

3 回答 3

1

在某些情况下,标准输入是不可搜索的,例如,如果它是从管道或终端重定向的。例如,有一个rew带有内容的文件:

#!/bin/bash
echo 123
perl -E 'seek(STDIN,0,0) or die "$!"' #the rewind

并将其用作

bash -s < rew

印刷

123
123
...
123
^C

因此,当 STDIN 可搜索时,它将按预期工作,但从管道尝试相同,例如:

cat rew | bash -s   #the cat is intentional here :)

将打印

123
Illegal seek at -e line 1.

所以,当你的 c 程序rewind试图在不可搜索的输入中搜索时,它应该打印一个错误。

于 2017-03-10T09:41:26.023 回答
0

您可以使用以下脚本演示此(令人惊讶的)行为:

$ cat test.sh
cut -f 1
printf '%s\t%s\n' script file

如果将它传递给 shell 的标准输入,则第 2 行以后应该成为cut命令的标准输入:

$ sh < test.sh
printf '%s\t%s\n' script file

如果您改为正常运行它并按字面意思输入fooTabbarEnterCtrl-d,您应该看到标准输入正常链接:

$ sh test.sh 
foo     bar
foo
script  file

注释:

$ sh test.sh # Your command
foo     bar # Your input to `cut`
foo # The output of `cut`
script  file # The output of `printf`
于 2017-03-10T09:48:16.770 回答
0

当我在“shell.h”中使用定义为 1 的 NO_HISTORY 宏编译 FreeBSD ash 时,它会消耗整个文件并在我的倒带测试程序中仅输出 1234-1234。显然,FreeBSDash依赖 libedit 来保留 IO 行边界。

于 2017-03-11T04:37:31.953 回答