シェルからstdinが/ dev / nullかどうかを確認する方法は?


9

Linuxでは、シェルスクリプトが標準入力がnullデバイス(1、3)*からリダイレクトされているかどうか、理想的には何も読み取らないかどうかを確認する方法はありますか?

予想される動作は次のとおりです。

./checkstdinnull
-> no
./checkstdinnull < /dev/null
-> yes
echo -n | ./checkstdinnull
-> no

EDIT

mknod secretunknownname c 1 3
exec 6<secretunknownname
rm secretunknownname
./checkstdinnull <&6
-> yes

私は、入力デバイスの maj / min数を読み取る必要があるだけだと思います。しかし、シェルからそれを行う方法を見つけることができません。


*は必要ありません/dev/nullが、で手動で作成した場合でも nullデバイスがありますmknod


2
それが/dev/nullであるのか、それともttyではないのかを知る必要がありますか?
roaima 2018年

{ readlink -f /dev/stdin; } <&6execを使用してノードを削除した場合の出力は/root/secretunknownname (deleted)です。ファイルが削除されたことを示しているので、必要なもので十分ではありませんか?
Isaac

私が必要とする標準入力がヌルデバイスだったかどうかを知るために(実際には「必要」)。
Sylvain Leroux

2
私は(非常に貧弱に設計された!)産業システムで自分の道を見つけようとしています。また、workerユーティリティの入力をnullデバイスにマッピングすることもあれば、実際のハードウェアデバイスにマッピングすることもあります。どちらの場合も同じコードを使用しますが、メジャー/マイナー開発番号が異なります。私たちは、いつ(そしてなぜ!)どちらか一方を使用することを選択したことを追跡しようとしています。現時点では、statソリューションが唯一の有効なものです。
Sylvain Leroux、

「それで、あなたのEDITの例はあなたが説明する問題を実際に再現しません、あるいは:それはそうですか?」します。null デバイスからリダイレクトされた入力。通常はからアクセスします/dev/nullが、必須ではありません。「エイリアス」はmknod、私の例に示されているsを使用できます。
Sylvain Leroux

回答:


18

Linuxでは、次の方法で実行できます。

stdin_is_dev_null(){ test "`stat -Lc %t:%T /dev/stdin`" = "`stat -Lc %t:%T /dev/null`"; }

stat(1)のないLinux(例:ルーターのbusybox):

stdin_is_dev_null(){ ls -Ll /proc/self/fd/0 | grep -q ' 1,  *3 '; }

* bsdの場合:

stdin_is_dev_null(){ test "`stat -f %Z`" = "`stat -Lf %Z /dev/null`"; }

* BSDおよびSolarisのようなシステム、オン/dev/stdin/dev/fd/0および/proc/PID/fd/0実際のファイルに切り替わりますLinux上のように「魔法」シンボリックリンクではなく、キャラクタデバイス開いたとき。それらのパスのstat(2)は、開かれたファイル記述子のfstat(2)とは異なるものを返します。

つまり、GNU coreutilsがインストールされていても、Linuxの例はそこで機能しません。GNU stat(1)のバージョンが十分に新しい場合、-* bsdのstat(1)と同じように、引数を使用してファイル記述子0でfstat(2)を実行できます。

stdin_is_dev_null(){ test "`stat -Lc %t:%T -`" = "`stat -Lc %t:%T /dev/null`"; }

また、fstat(2)へのインターフェースを提供する任意の言語で移植性のあるチェックを行うことも非常に簡単です。でperl

stdin_is_dev_null(){ perl -e 'exit((stat STDIN)[6]!=(stat "/dev/null")[6])'; }

1
デバイスタイプとして/dev/null、IS 1:3、あなたはすぐにそれをテストすることができます。
RudiC 2018年

12
FWIW質問はシェル構文に関するものではありませんでした。私の問題に関しては、答えが私にstatコマンドを指摘するだけであったならば、私はすでにかなり満足しているでしょう。`$(支持者の間で編集戦争を開始する意味がわかりません。個人的には、私は好み$(...)、その構文を支持するいくつかのPOSIXの根拠(pubs.opengroup.org/onlinepubs/9699919799/xrat/…)がありますが、私は、質問。
Sylvain Leroux

2
誰か$( ... )がこの回答のコンテキストでバッククォートよりも優先される理由を説明できますか?
user1717828

「それはどのバグを修正しますか?」バグは修正されません。$(..)スタイル巣より簡単かつAIUIはPOSIX好ましいアプローチです。私は確かに編集戦争を始めるつもりはありませんでした。あなたの優れた答えを変えるのではなく、提案でコメントすることを好みました。
roaima 2018年

@ user1717828 わかりやすくするために、ここここここを参照してください。
roaima 2018年

16

Linuxでは、標準入力がからリダイレクトされるかどうかを判断するために、と同じデバイスとiノードがある/dev/nullかどうか/proc/self/fd/0を確認できます/dev/null

if [ /proc/self/fd/0 -ef /dev/null ]; then echo yes; else echo no; fi

/dev/stdin代わりに使用できます/proc/self/fd/0

標準入力がnullデバイスからリダイレクトされているかどうかを確認する場合は、メジャーデバイス番号とマイナーデバイス番号を比較する必要がありますstat(例:mosvyの回答も参照)。

if [ "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" ]; then echo yes; else echo no; fi

または、これがLinux固有であることを気にしない場合は、

if [ "$(stat -Lc %t:%T /dev/stdin)" = "1:3" ]; then echo yes; else echo no; fi

2
-ef、FILE1とFILE2が同じデバイスとiノードを参照している場合は真
Rui F Ribeiro

とてもかっこいい。bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null'その後、でもう一度行い</dev/nullます。+1
グレン・ジャックマン

1
/dev/stdin元のファイルへのシンボリックリンクであることはLinuxに固有であるため、すべてのこれらのソリューションは、とにかくLinux固有です。statベースのものは、GNUまたはbusyboxのが必要ですstat。GNUの最近のバージョンではstat、を使用stat -してfstat()Linux以外のシステムで動作するfd 0を実行できます。
ステファンChazelas

@Stéphane最後の部分はまさにOPが遭遇した状況です。そのため、私は両方のソリューションを記述し、/dev/nullとnullデバイスを区別しました。
Stephen Kitt

おっと、それを逃した。
ステファンChazelas

3

移植性のある方法で、stdinがnullデバイスであるかどうかを確認するには(オープンである/dev/nullかどうか((のコピーのように/dev/null)))、zshstat組み込みは、GNUとFreeBSDの両方をstat(IRIXではなく)先行している))):

zmodload zsh/stat
if [ "$(stat +rdev -f 0)" = "$(stat +rdev /dev/null)" ]; then
  echo stdin is open on the null device
fi

(ファイル記述子が読み取り専用、書き込み専用、または読み取り+書き込みモードで開いているかどうかは表示されないことに注意してください)。

Linuxでのみ(たとえば、現在の/dev/nullファイルで)開いていることを確認するには/some/chroot/dev/null(他のシステムで/dev/stdin開くように動作する特別なデバイスではなく、fd 0で開いているファイルへのシンボリックリンクとして実装されている場合dup(0)):

if [ /dev/stdin -ef /dev/null ]; then
  echo stdin is open on /dev/null
fi

Linux以外では、以下を試すことができます。

if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
  echo stdin is open on /dev/null
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.