Você pode desvincular um canal nomeado imediatamente após anexá-lo ao processo atual, o que praticamente resulta em um canal anônimo:
# create a temporary named pipe
PIPE=$(mktemp -u)
mkfifo $PIPE
# attach it to file descriptor 3
exec 3<>$PIPE
# unlink the named pipe
rm $PIPE
...
# anything we write to fd 3 can be read back from it
echo 'Hello world!' >&3
head -n1 <&3
...
# close the file descriptor when we are finished (optional)
exec 3>&-
Se você realmente deseja evitar pipes nomeados (por exemplo, o sistema de arquivos é somente leitura), sua idéia de "entender os descritores de arquivos" também funciona. Observe que isso é específico do Linux devido ao uso de procfs.
# start a background pipeline with two processes running forever
tail -f /dev/null | tail -f /dev/null &
# save the process ids
PID2=$!
PID1=$(jobs -p %+)
# hijack the pipe's file descriptors using procfs
exec 3>/proc/$PID1/fd/1 4</proc/$PID2/fd/0
# kill the background processes we no longer need
# (using disown suppresses the 'Terminated' message)
disown $PID2
kill $PID1 $PID2
...
# anything we write to fd 3 can be read back from fd 4
echo 'Hello world!' >&3
head -n1 <&4
...
# close the file descriptors when we are finished (optional)
exec 3>&- 4<&-
Embora nenhuma das conchas que conheço possa fabricar tubos sem bifurcação, algumas têm melhor do que o oleoduto básico.
No bash, ksh e zsh, assumindo que o seu sistema suporta
/dev/fd
(a maioria dos dias de hoje), você pode vincular a entrada ou a saída de um comando a um nome de arquivo:<(command)
expande para um nome de arquivo que designa um canal conectado à saídacommand
e>(command)
expande para um nome de arquivo que designa um canal conectado à entrada decommand
. Esse recurso é chamado de substituição de processo . Seu objetivo principal é canalizar mais de um comando para dentro ou fora de outro, por exemplo,Isso também é útil para combater algumas das deficiências dos tubos de casca básicos. Por exemplo,
command2 < <(command1)
é equivalente acommand1 | command2
, exceto que seu status é o decommand2
. Outro caso de usoexec > >(postprocessing)
é equivalente, mas mais legível do que colocar todo o restante do script{ ... } | postprocessing
.fonte
pipe:[123456]
). O Emacs vê que o destino do link simbólico não é um nome de arquivo existente e o confunde o suficiente para não ler o arquivo (pode haver uma opção para fazê-lo ler de qualquer maneira, embora o Emacs não goste de abrir um pipe como um arquivo). de qualquer maneira).O Bash 4 tem coprocessos .
fonte
Em outubro de 2012, essa funcionalidade ainda não parece existir no Bash, mas o coproc pode ser usado se tudo o que você precisa para pipes não nomeados / anônimos é conversar com um processo filho. O problema com o coproc neste momento é que aparentemente apenas um é suportado por vez. Não consigo descobrir por que a coproc recebeu essa limitação. Eles deveriam ter sido um aprimoramento do código de plano de fundo da tarefa existente (o & op), mas essa é uma pergunta para os autores do bash.
fonte
coproc THING { dothing; }
agora seus FDs estão${THING[*]}
e você pode executar,coproc OTHERTHING { dothing; }
enviar e receber itens para e de ambos.man bash
, sob o título BUGS, eles dizem o seguinte: Pode haver apenas um coprocesso ativo por vez . E você recebe um aviso se iniciar um segundo coproc. Parece funcionar, mas não sei o que explode em segundo plano.Embora a resposta da @ DavidAnderson cubra todas as bases e ofereça algumas boas salvaguardas, a coisa mais importante que ela revela é que colocar as mãos em um cano anônimo é tão fácil quanto
<(:)
, desde que você permaneça no Linux.Portanto, a resposta mais curta e simples à sua pergunta é:
No macOS, ele não funcionará; será necessário criar um diretório temporário para abrigar o fifo nomeado até que você o redirecione. Eu não sei sobre outros BSDs.
fonte
exec
for passado e um anônimo anônimo que é aberto apenas para leitura,exec
não deve permitir que esse anônimo seja aberto para leitura e gravação usando um descritor de arquivo personalizado. Você deve receber uma-bash: /dev/fd/5: Permission denied
mensagem, que é o que o macOS emite. Eu acredito que o bug é que o Ubuntu não produz a mesma mensagem. Eu estaria disposto a mudar de idéia se alguém pudesse produzir documentação dizendo queexec 5<> <(:)
é explicitamente permitido.open(..., O_RDWR)
em uma extremidade de tubo unidirecional fornecida pela substituição e que o transforma em um tubo bidirecional em um FD. Você provavelmente está certo de que não se deve confiar nisso. :-D Saída usando o piperw do execline para criar o pipe e, em seguida, redirecionando-o com o bash<>
: libranet.de/display/0b6b25a8-195c-84af-6ac7-ee6696661765exec 5<>
, digitefun() { ls -l $1; ls -lH $1; }; fun <(:)
.A seguinte função foi testada usando
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
. O sistema operacional era o Ubuntu 18. Essa função usa um único parâmetro, que é o descritor de arquivo desejado para o FIFO anônimo.A seguinte função foi testada usando
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
. O sistema operacional era o macOS High Sierra. Essa função inicia criando um FIFO nomeado em um diretório temporário conhecido apenas pelo processo que o criou . Em seguida, o descritor de arquivo é redirecionado para o FIFO. Finalmente, o FIFO é desvinculado do nome do arquivo excluindo o diretório temporário. Isso torna o FIFO anônimo.As funções acima podem ser combinadas em uma única função que funcionará nos dois sistemas operacionais. Abaixo está um exemplo dessa função. Aqui, é feita uma tentativa de criar um FIFO verdadeiramente anônimo. Se malsucedido, um FIFO nomeado será criado e convertido em um FIFO anônimo.
Aqui está um exemplo de criação de um FIFO anônimo e, em seguida, escrevendo algum texto no mesmo FIFO.
Abaixo está um exemplo de leitura de todo o conteúdo do FIFO anônimo.
Isso produz a seguinte saída.
O comando abaixo fecha o FIFO anônimo.
Referências:
Criar um canal anônimo para uso posterior
Arquivos em diretórios publicamente graváveis são perigosos para a
segurança de scripts do shell
fonte
Usando a ótima e brilhante resposta de htamas, modifiquei-a um pouco para usá-la em uma linha, aqui está:
fonte