bash 输入重定向破坏标准输入
bash input redirection breaks stdin
我有一个看起来像这样的程序:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
int enable_keyboard() {
struct termios new_term_attr;
tcgetattr(fileno(stdin), &new_term_attr);
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
return tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
int main() {
errno = 0;
unsigned char field[H][W];
fill (field);
char c = enable_keyboard();;
while(1) {
read(0, &c, 1);
printf("%d ", c);
}
}
它从 stdin 读取单个字符并无限显示它(以检查 enable_keybord 是否正常工作)。
问题是,当我 运行 这个带有输入重定向的程序(第 ./a.out < test.txt
行)时,它会破坏所有输入并且 errno
设置为 25.
还有 tcsetattr
returns -201 当它应该 return 0 或 -1.
我试图在 tcsetattr
之前用 scanf
清除 stdin
并完全禁用 tcsetattr
但结果输入重定向完全挂起所有输入。
没有输入重定向,一切正常,所以我想也许 bash 对 stdin 做了一些事情,所以它在程序中死机了。
有解决问题的想法吗?
errno
25 = "不适合设备的 ioctl";您正在对文件执行终端操作。您没有检查 tcgetattr()
中的 return。出错时,它设置 errno
,如果文件描述符不代表终端,则设置为 ENOTTY
。所以:
int enable_keyboard()
{
struct termios new_term_attr;
int status = -1 ;
if( tcgetattr(fileno(stdin), &new_term_attr) == 0 )
{
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
status = tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
return status ;
}
然而,这不会解决您的“挂起”问题 - 正如您提到的,您的程序无限期循环 - while 循环不会在 EOF 处终止。问题是 read()
没有明确指示 EOF——而是 return 为零——对于终端输入来说,这意味着没有字符。在那种情况下:
char c = 0 ;
bool is_file = enable_keyboard() != 0 ;
bool terminate = false ;
while( !terminate )
{
terminate = read(0, &c, 1) == 0 && is_file ;
printf("%d ", c);
}
综合起来:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <stdbool.h>
int enable_keyboard()
{
struct termios new_term_attr;
int status = -1 ;
if( tcgetattr(fileno(stdin), &new_term_attr) == 0 )
{
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
status = tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
return status ;
}
int main()
{
errno = 0;
char c = 0 ;
bool is_file = enable_keyboard() != 0 ;
bool terminate = false ;
while( !terminate )
{
terminate = read(0, &c, 1) == 0 && is_file ;
printf("%d ", c);
}
return 0 ;
}
我有一个看起来像这样的程序:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
int enable_keyboard() {
struct termios new_term_attr;
tcgetattr(fileno(stdin), &new_term_attr);
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
return tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
int main() {
errno = 0;
unsigned char field[H][W];
fill (field);
char c = enable_keyboard();;
while(1) {
read(0, &c, 1);
printf("%d ", c);
}
}
它从 stdin 读取单个字符并无限显示它(以检查 enable_keybord 是否正常工作)。
问题是,当我 运行 这个带有输入重定向的程序(第 ./a.out < test.txt
行)时,它会破坏所有输入并且 errno
设置为 25.
还有 tcsetattr
returns -201 当它应该 return 0 或 -1.
我试图在 tcsetattr
之前用 scanf
清除 stdin
并完全禁用 tcsetattr
但结果输入重定向完全挂起所有输入。
没有输入重定向,一切正常,所以我想也许 bash 对 stdin 做了一些事情,所以它在程序中死机了。
有解决问题的想法吗?
errno
25 = "不适合设备的 ioctl";您正在对文件执行终端操作。您没有检查 tcgetattr()
中的 return。出错时,它设置 errno
,如果文件描述符不代表终端,则设置为 ENOTTY
。所以:
int enable_keyboard()
{
struct termios new_term_attr;
int status = -1 ;
if( tcgetattr(fileno(stdin), &new_term_attr) == 0 )
{
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
status = tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
return status ;
}
然而,这不会解决您的“挂起”问题 - 正如您提到的,您的程序无限期循环 - while 循环不会在 EOF 处终止。问题是 read()
没有明确指示 EOF——而是 return 为零——对于终端输入来说,这意味着没有字符。在那种情况下:
char c = 0 ;
bool is_file = enable_keyboard() != 0 ;
bool terminate = false ;
while( !terminate )
{
terminate = read(0, &c, 1) == 0 && is_file ;
printf("%d ", c);
}
综合起来:
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <stdbool.h>
int enable_keyboard()
{
struct termios new_term_attr;
int status = -1 ;
if( tcgetattr(fileno(stdin), &new_term_attr) == 0 )
{
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
status = tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
}
return status ;
}
int main()
{
errno = 0;
char c = 0 ;
bool is_file = enable_keyboard() != 0 ;
bool terminate = false ;
while( !terminate )
{
terminate = read(0, &c, 1) == 0 && is_file ;
printf("%d ", c);
}
return 0 ;
}