2

我有一个调用xclip内部的脚本。像这样的东西:

#!/bin/bash
RESULT="some data"
echo $RESULT | xclip
echo $RESULT

xclipputs 将数据从它的标准输入放到剪贴板,生成一个后台线程来保存该缓冲区(这就是剪贴板在 X11 中的工作方式)并将其与 tty 分离。

如果我直接运行脚本,它会按预期工作:

$ ./script.sh
some data
$

但是,如果我尝试将其输出传递到管道中,它会挂起直到xclip后台进程结束(基本上,直到其他人将数据放入剪贴板)。

$ ./script.sh | ./another_script.sh # it hangs

我发现xclip有一个-f标志似乎可以解决这个问题。

从手册页:

当在输出级别设置为静默(默认值)的输入模式下调用 xclip 时,过滤器选项将导致 xclip 将通过管道传输到标准输入的文本打印回未修改的标准输出

但是,我试图理解为什么它会这样工作。

我创建了另一个行为相同的示例:

echo $(sleep 5 &)

另外,有人告诉我,在fish我的示例中没有-f标志。

所以,问题是:
1. 这是 shell ( bashand zsh) 的错误还是预期的行为?
2.-f标志如何影响这种行为?从手册页来看,它似乎不是很相关。
3. 如何使其他脚本(例如)以使用标志sleep的方式xclip工作?-f

4

1 回答 1

2

默认,

  1. 所有打开的文件都从父进程传递到子进程。和
  2. 当创建管道(A->B)时,进程 B 将不会在标准输入上获得 EOF 指示符,直到步骤 A 中的所有进程都关闭其 STDOUT。

结合以上,当你执行时/script.sh | ./another_script.sh,后台xclip会继承'script.sh'stdout(这是对的输入./another_script.sh),此时有两个进程(script.sh,xclip)连接到管道。只有当两者都将关闭 STDOUT(或将终止)时,./another_script.sh才会在管道上看到 EOF,并且能够退出(假设它正在等待输入 EOF)。

这些情况的解决方案是让后台进程关闭标准输出,从而允许管道完成。通常,如果需要输出,stdout 将被重定向到 stderr。最有可能的是,'-f' 关闭了 STDOUT。

每个人xclip,可以编写echo $RESULT | xclip -f(不需要额外的回显)以避免问题,并允许脚本作为管道的一部分运行

manfork和 manpipe提供详细信息。尤其是

男人 2 叉子:

  • 子继承父的一组打开文件描述符的副本。子文件中的每个文件描述符与父文件中的相应文件描述符引用相同的打开文件描述(请参阅 open(2))。这意味着两个文件描述符共享打开文件状态标志、文件偏移和信号驱动的 I/O 属性(参见 fcntl(2) 中 F_SETOWN 和 F_SETSIG 的描述)。

男人7管:

如果所有引用管道写入端的文件描述符都已关闭,则尝试从管道读取(2)将看到文件结束(读取(2)将返回 0)。

于 2019-12-03T13:18:46.670 回答