xsel 向哪个流打印无换行警告?

sag*_*aga 7 shell io-redirection stderr xsel

xsel 是一个可以从命令行访问系统剪贴板的程序。如果复制的内容末尾没有换行符,它会在剪贴板内容后打印警告,如下所示:

$ xsel -b
copied text
\ No newline at end of selection
Run Code Online (Sandbox Code Playgroud)

之前我一直以为这个警告是打印到标准错误上的,但是今天我发现即使标准错误和标准输出合并了,警告也不在。xsel-b |& less只打印复制的文本,没有警告。为什么它的行为是这样的?

Sté*_*las 5

请注意,这是xsel尚未发布的xsel. 由2008 年的这一变化引入。

X 选择包含不以换行符结尾的文本是很常见的。如果按原样转储,则会显示未终止的行。用旧壳子这样bash的显示器变成:

bash-4.4$ xsel -b
xselbash-4.4$
Run Code Online (Sandbox Code Playgroud)

(这里的剪贴板选择包含xsel)。下一个提示最终会附加到选择的内容中。

现代 shell 喜欢zshfish解决了检测最后一个命令的输出何时不以换行符结尾的问题,然后给你一个视觉指示。

zsh

prompt% xsel -p
xsel%
prompt%
Run Code Online (Sandbox Code Playgroud)

(指示缺少换行符%后的反向视频xsel)。

fish

prompt ~> xsel -p
x?
prompt ~>
Run Code Online (Sandbox Code Playgroud)

那些较新的xsel给你视觉指示本身:

bash-4.4$ xsel -b
xsel
\ No newline at end of selection
bash-4.4$
Run Code Online (Sandbox Code Playgroud)

现在,这仅在 xsel 在旧交互式 shell 的提示下运行时才有用。

特别是,“无换行符”指示在用作:

selection=$(xsel -b)
Run Code Online (Sandbox Code Playgroud)

(其中xsel的 stdout 是管道)或:

xsel -b > selection.txt
Run Code Online (Sandbox Code Playgroud)

(其中xsel的 stdout 是常规文件)。

这就是为什么xsel仅在 stdout 进入 tty 设备时才输出该指示的原因。

现在,它在哪里显示它?嗯,目的是在那个 tty 设备上显示它。如果你在 strace 下运行它,你会看到:

$ strace -e write ./xsel -b
write(1, "xsel", 4xsel)                     = 4
write(2, "\n\\ No newline at end of selectio"..., 34
\ No newline at end of selection
) = 34
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)

这证实了来源:它是 stderr 上的输出。当 stdout 不是终端时:

$ strace -e write ./xsel -b  > /dev/null
write(1, "$ strace -e write ./xsel -b | ca"..., 104) = 104
+++ exited with 0 +++
Run Code Online (Sandbox Code Playgroud)

它根本不是输出。现在有人可能会争辩说,当目的是将该通知输出到终端时,在 stderr 上输出有点愚蠢(stderr 可以重定向到日志文件,例如xsel -b 2> logfile),但是:

  • 通常,当 stdout 是终端设备时, stderr 也是。
  • 这意味着您可以在xsel -b 2> /dev/nullxsel -b | cat.
  • isatty()将用于未连接到终端的串口设备返回true。