【问题标题】:How do applications read lines from stdin without consuming existing buffered data from a pipe?应用程序如何在不消耗管道中现有缓冲数据的情况下从标准输入读取行?
【发布时间】:2012-12-06 04:04:22
【问题描述】:

执行以下命令:

mysql -u root -p < load_data.sql > output.tab

-p 标志告诉 mysql 客户端 - 一个 C 程序 - 为用户提供输入密码的交互式提示。

AFAIK,这样的输入通常通过向stderr 写入提示然后阻塞像gets 这样的调用来处理,它从标准输入读取一行。

但是 shell 已经打开了 load_data.sql 文件并将 mysql 客户端的 stdin 设置为其文件描述符 - 所以不应该调用 gets 只是从文件中获取第一行吗?

我最初的想法是程序会在读取一行之前搜索到结尾 - 但你不能在管道上进行这样的搜索!

那么这是如何工作的呢?有什么魔法吗?

【问题讨论】:

    标签: c unix posix pipe


    【解决方案1】:

    提示输入密码的应用程序通常实际上从标准输入读取它们,因为这会 (a) 导致密码出现在屏幕上,如果它是交互式输入的,并且(b) 当事情需要自动化时(例如,在其他人可以通过ps 看到的命令行中),鼓励在公开可见的地方使用纯文本密码。 PostgreSQL 的psql SQL shell 直接打开终端设备,我怀疑mysql也会这样做。

    一些快速搜索发现this related question。评价最高的答案提到了 GNU 函数 getpass(),它确实打开了与终端的直接连接,绕过了标准输入。我怀疑这个函数是大多数密码提示程序在 *nix 中使用的。

    【讨论】:

      【解决方案2】:

      这不是正在打开的管道,而是stdin 的重定向以指向文件。因此,您既拥有FILE*(即流),也拥有可以使用的普通文件描述符。对于较低级别的文件描述符,您可以执行一些查找操作,例如lseek() 等,可以与read() 一起使用以在文件中移动。

      如果您想在stdin 已重定向到文件时仍从控制终端读取数据,您只需打开控制终端以读取另一个文件描述符。您可以使用ctermid() 来确定您的进程的控制终端是什么,然后在另一个文件描述符上重新打开它。

      【讨论】:

      • 但无论如何,如果(例如在 Python 中)我要调用 sys.stdin.read(),我会将文件的内容读入缓冲区。应用程序如何改为从 tty 读取一行?
      • 你的意思是你还想从终端输入的用户那里读取动态输入?
      猜你喜欢
      • 2021-03-30
      • 2014-10-02
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      • 2013-08-05
      • 1970-01-01
      • 2011-05-18
      相关资源
      最近更新 更多