从 stdin 读取时如何保留 mplayer 中的控制台输入?

从 stdin 读取时如何保留 mplayer 中的控制台输入?

我正在玩命令行界面mplayer。我想用以下方式编写脚本

find /some/path/ -type f | grep -vif blacklist | mplayer -shuffle -playlist -

哪里blacklist有一个带有艺术家或歌曲名称的文本文件,当我有访客或我儿子在附近时,我宁愿忽略它(很多脏话......:D)

mplayer遇到该-字符时,它会禁用控制台输入。从手册页:

-noconsolecontrols
          Prevent MPlayer from reading key events from standard input.  
          Useful when reading data from standard input.  This is automatically  
          enabled when - is found on the command line. [snip]

这会阻止我在文件中查找并跳过个别歌曲。有趣的是,这适用于视频,因为视频窗口仍然接受通常的键盘输入。

如何恢复常规控制台输入?我想避免使用临时文件,尽管这当然是最简单的解决方案。-slave并且-input看起来不适合并且尝试-consolecontroles不起作用。

答案1

将输入提供给标准输入以外的文件描述符。

find /some/path/ -type f | grep -vif blacklist |
mplayer -shuffle -playlist /dev/fd/3 3<&0 </dev/tty

最后一行的解释:来自 grep 的数据来自标准输入,即文件描述符0. 除了 shell 中的标准输入之外,没有办法通过管道连接到任何地方,但我们可以做一些额外的管道工作。首先,我们将文件描述符 3 连接到文件描述符 0 所在的位置:3<&0。然后我们将文件描述符0(即标准输入)连接到终端:</dev/tty。我们告诉 mplayer 从文件描述符 3 读取播放列表; mplayer 需要一个文件名,因此我们传递它/dev/fd/3,当进程打开该文件时,其行为就像该进程中的文件描述符 3 一样。

请注意,重定向的顺序很重要,如果您的直觉错误,则会违反直觉。3<&0 </dev/ttyfd 3 从 fd 0 之前读取的位置读取,而 fd 0 从 读取/dev/tty</dev/tty 3<&0将同时读取 fd 0 和 fd 3 /dev/tty

答案2

这有点矫枉过正,但仍然可能是一个可行的解决方案:使用一些保险丝 文件系统支持过滤,例如过滤器FS或者rofs过滤揭示FS听起来也很方便 - 它隐藏缺少的文件user.public 扩展文件属性 ( xattr)

使用其中之一,您可能会告诉mplayer洗牌所有文件,从而保持stdin控制。 (不过,与创建两个播放列表相比,这是相当费力的。)

答案3

作为显式欺骗文件描述符的替代方法,在 Bash 中,您有一种便捷的方法来将管道作为 FD:

mplayer -shuffle -playlist <(find /some/path -type f -not -name '*.foo')

为此,您可以同时使用<(COMMAND)(管道输出命令)和(管道输出到命令)。>(COMMAND)它们通常使用 /proc/self/fd/ 文件名而不是 /dev/fd/ 文件名来工作,但效果是相同的,只是不需要所有的跑腿工作。

当然,请记住,mplayer 将在与播放列表文件相同的目录中查找非绝对播放列表内容文件;在本例中为 /proc/self/fd。 ( /dev/fd 解决方案也是如此。)您也无法从<()或中运行的命令捕获退出代码>(),除非每天通过命令的标准输出手动输入它们并在另一端挑选该数据对于命令行使用来说,这并不重要,但是对于脚本编写来说,这可能会很麻烦。

答案4

您可以使用xargs -o选项,例如:

find /some/path/ -type f -print0 2>/dev/null | grep -vif blacklist | xargs -0 -o mplayer -shuffle

man xargs:

-o, --open-tty

在执行命令之前,在子进程中将 stdin 重新打开为 /dev/tty。如果您希望 xargs 运行交互式应用程序,这非常有用。

相关内容