web-dev-qa-db-ja.com

'' cat "$ {1:-/ dev / stdin} | ...&> / dev / null ''がbashでは機能するがダッシュでは機能しないのはなぜですか?

脚本:

#!/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 &

Stdinだけが機能しないことがわかります(bashではstdin/fileで機能します)。
P.S。 verboseは、xclipをデーモン化しないようにするために使用されます。

4
droso

[この答えは、スクリプトの非同期パイプラインに関するものです。非推奨の&> bash演算子と、代わりに常に>output 2>&1を使用する必要がある理由については、 廃止および非推奨の構文 ]を参照してください。

#! /bin/sh
cat "${1:-/dev/stdin}" | ... &

ここでは、非同期で実行されているパイプラインがあります(&で終了しているため)。スクリプトから、つまりジョブコントロールが無効になっているシェルから開始されます。

標準 によると:

command1 & [command2 & ... ]

明示的なリダイレクトが実行される前の非同期リストの標準入力は、/dev/nullと同じプロパティを持つファイルに割り当てられていると見なされます。

問題は、dashkshmkshyashなどが、パイプラインを含む任意のコマンドとして「非同期リスト」を解釈し、リダイレクトすることです。 /dev/nullからの最初のコマンドのstdin:

$ 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は、元のstdinがttyである場合のみ/dev/nullからリダイレクトします。他の種類のファイルではありません。

$ zsh -c 'readlink /proc/self/fd/0 &' </dev/tty
/dev/null
$ zsh -c 'readlink /proc/self/fd/0 &' </dev/zero
/dev/zero

すべてのシェルで機能する回避策は、stdinを別のファイル記述子に複製し、そこから最初のコマンドのstdinをリダイレクトすることです。

#! /bin/sh
exec 3<"${1:-/dev/stdin}"
cat <&3 | timeout 30 xclip -i -selection clipboard -verbose -r >/dev/null 2>&1 &
5
mosvy

&>はバシズムです。POSIXシェルの場合は>/dev/null 2>&1に変更する必要があります

10
jesse_b

dashはPOSIX標準として位置付けられています。 POSIXのみ[n]>リダイレクト。しかし、bashは多くの独自の機能を導入しています。 &>はそれらの1つであり、出力記述子(stderrおよびstdout)を意味します。

bash and dash の互換性に関する記事を読んでください。

多分あなたは役立つ checkbashisms スクリプトがbash固有の指示を見つけるのを助けることができるユーティリティ。

7
Yurij Goncharuk