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
只打印复制的文本,没有警告。为什么它的行为是这样的?
请注意,这是xsel
尚未发布的xsel
. 由2008 年的这一变化引入。
X 选择包含不以换行符结尾的文本是很常见的。如果按原样转储,则会显示未终止的行。用旧壳子这样bash
的显示器变成:
bash-4.4$ xsel -b
xselbash-4.4$
Run Code Online (Sandbox Code Playgroud)
(这里的剪贴板选择包含xsel
)。下一个提示最终会附加到选择的内容中。
现代 shell 喜欢zsh
或fish
解决了检测最后一个命令的输出何时不以换行符结尾的问题,然后给你一个视觉指示。
与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
),但是:
xsel -b 2> /dev/null
比xsel -b | cat
.isatty()
将用于未连接到终端的串口设备返回true。