Stdin
執行的程序未從標準輸入讀取
我有一個程序 A 執行以下操作:
- 從輸入中讀取 2 個字節
- 列印讀取輸入
exec
進入程序 B。程序 B 執行以下操作
- 從輸入中讀取 2 個字節
- 列印輸入
具體來說,以下是程序 A、B:
A:
#include <unistd.h> #include <stdio.h> int main(){ char a[3]; fgets(a, 3, stdin); printf("%s\n", a); char* args[] = {NULL}; execv("./read2", args); }
乙:
#include <stdio.h> int main(){ char a[] = "hy"; fgets(a, 3, stdin); printf("%s\n", a); }
當我像這樣執行它時
echo 'abcd' | ./A
,我期望得到以下輸出ab cd
但我明白了
為什麼不
B
從其標準輸入讀取?
TLDR:如果後續程序需要從父級停止的位置準確讀取,則父級必須使用無緩衝 IO。
使用非緩衝 IO,程序執行正確:
#include <stdio.h> #include <string.h> #include <unistd.h> char buf[3]; int main(int argc, char *argv[]) { read(STDIN_FILENO, buf, 2); printf("%s '%s'\n", *argv, buf); if (strcmp(*argv, "./childtu") == 0) return 0; execl("./readtwo", "./childtu", (char *) 0); }
通過執行
$ make readtwo cc readtwo.c -o readtwo $ echo abcdefg | ./readtwo ./readtwo 'ab' ./childtu 'cd' $
父母中的緩衝 IO(通過
fgets
)是問題所在,因為如果輸入比父母提前讀取的輸入多,孩子只能從標準輸入中讀取:#include <stdio.h> #include <string.h> #include <unistd.h> char buf[3]; int main(int argc, char *argv[]) { fgets(buf, 3, stdin); printf("%s '%s'\n", *argv, buf); if (strcmp(*argv, "./childtu") == 0) return 0; execl("./readtwo", "./childtu", (char *) 0); }
如果好奇,可以對確切的緩衝區大小進行二進制搜尋,或者查看核心中設置的內容:
$ perl -e 'print(("a")x99999)' | ./readtwo ./readtwo 'aa' ./childtu 'aa' $
使用(或類似的)我們可以從標準輸入(fd 0)
strace
中觀察到父程序有多少:read
$ echo asdf | strace -o blah ./readtwo ./readtwo 'as' ./childtu '' $ fgrep 'read(0' blah read(0, "asdf\n", 4096) = 5 read(0, "", 4096) = 0 $
在這裡,父程序想要 4096 個字節(但只有 5 個字節),而
exec
’d 程序得到了零,因為什麼都沒有了。因此,如果這是一個問題,請不要在父程序中使用緩衝讀取。