Bash
為什麼 ‘‘cat ‘${1:-/dev/stdin} | … &>/dev/null’’ 在 bash 中有效,但在 dash 中無效?
腳本:
#!/bin/sh # # reads stdin/file and copies it to clipboard # clears it after 30s # cat "${1:-/dev/stdin}" | timeout 30 xclip -i -selection clipboard -r -verbose &>/dev/null &
我可以看到只有標準輸入不起作用(使用 bash 它適用於標準輸入/文件)。
PS verbose 用於使 xclip 不被守護。
[這個答案是關於腳本中的非同步管道;對於不推薦使用的
&>
bash 運算符以及為什麼應該始終使用>output 2>&1
,請參閱過時和不推薦使用的語法]#! /bin/sh cat "${1:-/dev/stdin}" | ... &
在這裡,您有一個非同步執行的管道(因為由 終止
&
),從腳本啟動,即從禁用作業控制的外殼開始。根據標準:
command1 & [command2 & ... ]
在執行任何顯式重定向之前,非同步列表的標準輸入應被視為已分配給與 具有相同屬性的文件
/dev/null
。問題是 ,
dash
,ksh
,mksh
等yash
將“非同步列表”解釋為任何命令,包括管道,並將重定向第一個命令的標準輸入/dev/null
:$ echo foo | dash -c 'cat | tr fo FO & echo DONE' DONE $ echo | dash -c 'readlink /proc/self/fd/0 | cat & echo DONE' DONE /dev/null
但
bash
只會將其解釋為“簡單命令”,並且只會/dev/null
在它不是管道的一部分時重定向其標準輸入:$ echo foo | bash -c 'cat | tr fo FO & echo DONE' DONE FOO $ echo | bash -c 'readlink /proc/self/fd/0 | cat & echo DONE' DONE pipe:[69872] $ echo | bash -c 'readlink /proc/self/fd/0 & echo DONE' DONE /dev/null $ bash -c 'cat | tr a A & echo DONE' DONE cat: -: Input/output error
zsh
只會/dev/null
在原始標準輸入是 tty 時重定向它,而不是當它是其他類型的文件時:$ zsh -c 'readlink /proc/self/fd/0 &' </dev/tty /dev/null $ zsh -c 'readlink /proc/self/fd/0 &' </dev/zero /dev/zero
適用於所有 shell 的解決方法是將標準輸入複製到另一個文件描述符中,並從中重定向第一個命令的標準輸入:
#! /bin/sh exec 3<"${1:-/dev/stdin}" cat <&3 | timeout 30 xclip -i -selection clipboard -verbose -r >/dev/null 2>&1 &
&>
是一個 bashism,您必須將其更改>/dev/null 2>&1
為 POSIX shell