Eu gostaria que um script bash produzisse informações adicionais para os descritores de arquivo (FDs) maiores ou iguais a 3, quando abertos. Para testar se um FD está aberto, criei o seguinte truque:
if (printf '' 1>&3) 2>&-; then
# File descriptor 3 is open
else
# File descriptor 3 is not open
fi
Isso é suficiente para minhas necessidades, mas estou curioso para saber se existe uma maneira mais idiomática de testar se um FD é válido. Estou especialmente interessado em saber se existe um mapeamento do fcntl(1)
syscall para um comando shell, o que permitiria a recuperação de sinalizadores de FD ( O_WRONLY
e O_RDWR
para testar se o FD é gravável O_RDONLY
e O_RDWR
para testar se o FD é legível).
fonte
<>
? O shell não vai ler de seu stderr, por que você deseja abri-lo em leitura + gravação? O que você quer dizer com o que aconteceu com o intrínseco? ?Na descrição de uso do aplicativo POSIX, você encontrará o seguinte:
command
É por isso que você pode simplesmente fazer:
Ou...
Que escreverá a sequência seguida por um
\n
ewline para stdout ou 3 e ainda transmitirá um status de saída diferente de zero quando 3 não estiver aberto, porque as contas feitas$?
acabam falhando em converter o octal 08 para % decimal, mas não são absolutamente truncadas o octal 00 .Ou...
Mas se você estiver usando
ksh93
, basta:Para uma lista de descritores de arquivos abertos. Adicione
-l
para ver para onde eles vão.fonte
Os descritores de arquivos abertos podem ser encontrados em
/proc/<pid>/fd
. Para listar, por exemplo, os descritores de arquivo aberto do shell atual que você pode emitir, ols -l /proc/$$/fd
que deve fornecer algo como:Quando você abre um arquivo usando:
Deve ser listado por um novo
ls -l /proc/$$/fd
:Se você fechar o descritor de arquivo novamente,
exec 7>&-
ele também não estará listado/proc/$$/fd
.fonte
pfiles <pid>
para ver qual descritor de arquivo está conectado a qual arquivo enquantols -l
exibe a conexão no Linux.[ -e /proc/$$/fd/3 ]
, mas prefiro não confiar nos procfs, pois ele foi descontinuado no FreeBSD e possivelmente em outros setores também.pfiles <pid>
oulsof -p <pid>
ver quais descritores de arquivo estão abertos./proc
não existe no OpenBSD. No FreeBSD e NetBSD, ele deve sermount
explicado explicitamente e/proc/<PID>
não possui um subdiretóriofd
.Seu truque parece fofo; mas de uma maneira idiomática, eu me pergunto por que você não usou:
fonte
{ true >&3; } 2> /dev/null
para evitar o garfo. Ou{ command exec >&3; } 2> /dev/null
se você deseja redirecionar o stdout para ele.{ true >&3; } 2> /dev/null
também não afetará o ambiente atual e não será bifurcado (exceto no shell Bourne). Quero dizer que(exec 1>&3) 2>&-
retornará true para um fd aberto no modo somente leitura.exec
sendo um builtin especial sairá do shell se falhar (para o bash, somente quando estiver no modo de conformidade com POSIX).command exec
impede isso.true
não é um builtin especial. Note-se queexec
ecommand exec
afetam o ambiente atual (é por isso que eu disse , se você deseja redirecionar stdout a ele ).Se você estiver interessado em uma solução de baixo garfo para usá-la repetidamente, sugiro esta função:
E aqui está o que ele produz com um
zsh
:fonte
exec >&3
, o casco é eliminado quando o 3 não estiver aberto.zsh
ebash
. Você poderia fornecer o shell no qual a falhaexec
causou umexit
?bash
fazerset -o posix
e tente novamente. Emzsh
... eu acho que é uma questão de definir o env varPOSIX_BUILTINS
para um valor não nulo - mas eu esqueço de imediato. De qualquer forma,zsh
não é um shell que tenta conformidade com POSIX e, portanto, é definitivamente fora do padrão. Ambas as conchas evitam a compatibilidade com o que alguns acreditam ser conveniente.set -o posix
uma tentativa é bem-sucedida.Isso parece super fácil (ver comentários):
Como um extra ... O teste [-r file] não indica se algum dado está realmente esperando para ser lido (/ dev / null passa neste teste (consulte os comentários)).
É necessário algum número pequeno para o argumento de tempo limite (read -t) ou dados que precisam de algum cálculo podem ser perdidos. O teste legível ([-r arquivo]) é necessário ou o comando read será bombardeado se o arquivo não for legível. Na verdade, isso não lerá nenhum dado porque a contagem de bytes é zero (leia -N 0).
fonte
/proc/<pid>/fdinfo/<fd>
, que lista todos os modos de arquivos abertos emflags:
- veja aqui . Por que a sua segunda parte (mesmo depois de corrigir o erro gritante):read -t .1 -N0 <&4
não informa se há dados a serem lidos no fd 4: tente com4</dev/null
.[ -r /proc/$$/fd/$FD ]
é claro, não informa se o descritor de arquivo$FD
é legível, mas se o arquivo do qual foi aberto pode ser aberto novamente , com outro descritor de arquivo, para leitura:exec 7>/tmp/foo; [ -r /proc/$$/fd/7 ] && echo fd 7 can be read from && cat <&7
A questão é bastante antiga - mas de qualquer maneira - por que simplesmente não usar builtins?
Resultado:
Então, para responder à pergunta - sugeriria:
fonte
-t
não testa se um descritor de arquivo é válido, mas se está conectado a um tty. Coloque um prefixo aecho yup |
no seu script e dirá que0 is INVALID FD
, embora de fato seja muito válido, um pipe.