Como verificar se stdin é / dev / null do shell?

8

No Linux, existe uma maneira de um script de shell verificar se sua entrada padrão é redirecionada do dispositivo nulo (1, 3) * , de preferência sem ler nada?

O comportamento esperado seria:

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

EDIT

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

Eu suspeito que eu "apenas" precise ler o número maj / min do dispositivo de entrada . Mas não consigo encontrar uma maneira de fazer isso a partir do shell.

* Não é necessário apenas /dev/null , mas qualquer dispositivo nulo mesmo se criado manualmente com mknod .     
por Sylvain Leroux 26.11.2018 / 16:02

3 respostas

18

No linux, você pode fazer isso com:

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

Em um linux sem stat (1) (por exemplo, o busybox no seu roteador):

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

Em * bsd:

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

Em sistemas como * bsd e solaris, /dev/stdin , /dev/fd/0 e /proc/PID/fd/0 não são links simbólicos "mágicos" como no linux, mas dispositivos de caracteres que mudam para o arquivo real quando abertos . Um stat (2) em seu caminho retornará algo diferente de um fstat (2) no descritor de arquivo aberto.

Isso significa que o exemplo do linux não funcionará lá, mesmo com o GNU Coreutils instalado. Se as versões do GNU stat (1) forem recentes o suficiente, você pode usar o argumento - para permitir que ele faça um fstat (2) no descritor de arquivo 0, assim como o stat (1) de * bsd:

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

Também é muito fácil fazer o teste portably em qualquer idioma que ofereça uma interface para o fstat (2), por exemplo. em perl :

stdin_is_dev_null(){ perl -e 'exit((stat STDIN)[6]!=(stat "/dev/null")[6])'; }
    
por 26.11.2018 / 16:32
15

No Linux, para determinar se a entrada padrão é redirecionada de /dev/null , você pode verificar se /proc/self/fd/0 tem o mesmo dispositivo e inode que /dev/null :

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

Você pode usar /dev/stdin em vez de /proc/self/fd/0 .

Se você quiser verificar se a entrada padrão é redirecionada do dispositivo nulo, é necessário comparar números de dispositivos maiores e menores, por exemplo, usando stat (consulte também resposta de mosvy ):

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

ou, se você não se importa com isso específico do Linux ,

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

Portável, para verificar se stdin é o dispositivo null (abra em /dev/null ou não (como uma cópia de /dev/null )), com zsh (cujo stat embutido é anterior ao GNU e FreeBSD stat pelo caminho (não IRIX 'embora))):

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

(note que ele não diz se o descritor de arquivos estava aberto no modo somente leitura, somente gravação ou leitura + gravação).

Para verificar se ele está aberto no arquivo /dev/null atual especificamente (não /some/chroot/dev/null , por exemplo), somente no Linux (onde /dev/stdin é implementado como um link simbólico para o arquivo aberto no fd 0 em vez de um dispositivo especial que quando aberto age como um dup(0) em outros sistemas):

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

No não-Linux, você pode tentar:

if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
  echo stdin is open on /dev/null
fi
    
por 26.11.2018 / 20:04