Как проверить, является ли stdin / dev / null из оболочки?


9

В Linux есть ли способ для сценария оболочки проверить, перенаправлен ли его стандартный ввод с нулевого устройства (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

Я подозреваю, что мне «просто» нужно прочитать число маж / мин устройства ввода . Но я не могу найти способ сделать это из оболочки.


* Нет необходимости просто /dev/null, но любое нулевое устройство, даже если оно создано вручную с помощью mknod.


2
Вам нужно знать, если это /dev/null, или просто это не tty?
— Ройма

Выход { readlink -f /dev/stdin; } <&6для случая , когда вы использовали Exec и удалить узел /root/secretunknownname (deleted). Как показывает, что файл был удален: Разве этого недостаточно для того, что вам нужно?
— Исаак

Мне нужно (на самом деле «необходимо»), чтобы знать, был ли стандартный ввод нулевым устройством.
— Сильвен Леру

2
Я пытаюсь найти свой путь в (очень плохо спроектированной!) Промышленной системе. И иногда он отображает ввод рабочей утилиты на нулевое устройство или, иногда, на фактическое аппаратное устройство. В обоих случаях используется один и тот же код, но с разными старшими / младшими номерами разработчиков. Мы пытаемся отследить, когда (и почему!) Он иногда выбирал один или другой. На данный момент statрешение работает только одно.
— Сильвен Леру

«Итак, пример вашего EDIT не воспроизводит проблему, которую вы описываете, или: да?» Оно делает. Ввод перенаправлен с нулевого устройства . К которому обычно обращаются через /dev/null, но не обязательно. Вы можете "псевдоним" с mknods, иллюстрируется в моем примере.
— Сильвен Леру

Ответы:


18

На Linux вы можете сделать это с:

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

В Linux без stat (1) (например, 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) в дескрипторе открытого файла.

Это означает, что пример Linux не будет работать там, даже с установленным GNU coreutils. Если версии GNU stat (1) достаточно недавние, вы можете использовать -аргумент, чтобы позволить ему выполнить fstat (2) для файлового дескриптора 0, так же как stat (1) из * bsd:

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есть 1:3, вы можете проверить это немедленно.
— RudiC

12
FWIW вопрос был не о синтаксисе оболочки. Что касается моей проблемы, если бы ответ только указал мне на statкоманду, я был бы уже вполне удовлетворен. Я не вижу смысла в открытии войны редактирования между `и $(сторонников. Лично я предпочитаю, $(...)и есть некоторые обоснования POSIX в пользу этого синтаксиса ( pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) Но я не вижу смысла в даунтинге, если нет правильного ответа на что-то, не связанное с вопрос.
— Сильвен Леру

2
Может ли кто-нибудь объяснить, почему $( ... )в контексте этого ответа предпочтительнее обратных кавычек?
— user1717828

" какую ошибку это исправляет "? Это не исправляет ошибку. В $(..)гнездах стиля легко и AIUI является POSIX предпочтительного подхода. Я, конечно, не собирался начинать редактирование войны, предпочитая комментировать с предложением, а не менять свой отличный ответ.
— Ройма

@ user1717828 смотрите здесь и здесь и здесь для некоторой ясности.
— Ройма

16

В Linux, чтобы определить, перенаправлен ли стандартный ввод /dev/null, вы можете проверить, /proc/self/fd/0имеет ли то же устройство и inode, что и /dev/null:

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

Вы можете использовать /dev/stdinвместо /proc/self/fd/0.

Если вы хотите проверить, перенаправлен ли стандартный ввод с нулевого устройства, вам нужно сравнить старшие и младшие номера устройств, например, используя 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, True, если FILE1 и FILE2 относятся к одному и тому же устройству и индоду
— 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()на FD 0 , который будет затем работать на системах , отличных от Linux.
— Стефан Шазелас

@ Стефан, последняя часть - это именно та ситуация, с которой столкнулся ОП, поэтому я написал оба решения, различая /dev/nullнулевое устройство и устройство.
— Стивен Китт

Упс, пропустил это.
— Стефан Шазелас

3

Для проверки того, что stdin - это nullустройство (открыто /dev/nullили нет (как копия /dev/null)), с zsh(чья statвстроенная версия предшествует 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

(обратите внимание, что в нем не указано, был ли дескриптор файла открыт в режиме «только чтение», «только запись» или «чтение + запись»).

Чтобы проверить, что он открыт /dev/nullконкретно /some/chroot/dev/nullдля текущего файла (не, например), только в Linux (где /dev/stdinон реализован в виде символической ссылки на файл, открытый на fd 0 вместо специального устройства, которое при открытии действует как a 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.