Eu tenho um programa que produz informações úteis, stdout
mas também lê stdin
. Quero redirecionar sua saída padrão para um arquivo sem fornecer nada na entrada padrão. Até agora, tudo bem: eu posso fazer:
program > output
e não faça nada no tty.
No entanto, o problema é que eu quero fazer isso em segundo plano. Se eu fizer:
program > output &
o programa será suspenso ("suspendido (entrada tty)").
Se eu fizer:
program < /dev/null > output &
o programa termina imediatamente porque alcança EOF.
Parece que o que preciso é canalizar para program
algo que não faz nada por um período indefinido de tempo e não lê stdin
. As abordagens a seguir funcionam:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
No entanto, tudo isso é muito feio. Não tem que ser uma maneira elegante, usando utilitários Unix padrão, para "não fazer nada, por tempo indeterminado" (parafraseando man true
). Como eu consegui isso? (Meus principais critérios de elegância aqui: sem arquivos temporários; sem espera ocupada ou ativações periódicas; sem utilitários exóticos; o mais curto possível).
su -c 'program | output &' user
. Estou prestes a fazer uma pergunta semelhante com a criação de trabalhos em segundo plano como um método aceitável para lidar com um "serviço / daemon". Também notei que não era possível redirecionarSTDERR
sem também redirecionarSTDOUT
. A solução onde o Programa enviaSTDOUT
aSTDIN
de programB, então redirecionaSTDERR
para um arquivo de log:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
ele sairá do seu programa?Respostas:
Nos shells que os suportam (ksh, zsh, bash4), você pode iniciar
program
como um co-processo .ksh
:program > output |&
zsh
,bash
:coproc program > output
Isso começa
program
em segundo plano com sua entrada redirecionada de apipe
. A outra extremidade do tubo está aberta para a concha.Três benefícios dessa abordagem
program
morrer (usewait
para esperar)program
terminará (entreeof
em seu stdin se o shell sair).fonte
tail -f /dev/null
não é o ideal, pois ele faz uma leitura a cada segundo/dev/null
(as versões atuais do GNU tail no Linux usando inotify há realmente um bug ).sleep inf
ou seu equivalente mais portátil,sleep 2147483647
são abordagens melhores para um comando que fica lá sem fazer nada IMO (observe que elesleep
é construído em alguns shells comoksh93
oumksh
).Eu não acho que você vai ficar mais elegante que o
que você já sugeriu (supondo que esse uso seja inotificado internamente, não deve haver pesquisas ou despertares; portanto, além de ter uma aparência estranha, deve ser suficiente).
Você precisa de um utilitário que funcione indefinidamente, manterá o stdout aberto, mas não gravará nada no stdout e não sairá quando o stdin estiver fechado. Algo como
yes
realmente escreve para stdout.cat
sairá quando o stdin estiver fechado (ou o que você redirecionar para ele estiver pronto). Eu acho quesleep 1000000000d
pode funcionar, mastail
é claramente melhor. Minha caixa Debian tem umtailf
comando que encurta um pouco.Tomando uma abordagem diferente, que tal executar o programa
screen
?fonte
tail -f /dev/null
abordagem da melhor maneira e também a acho elegante o suficiente, pois o uso do comando corresponde muito bem ao objetivo pretendido.strace tail -f /dev/null
parece quetail
utilizainotify
e que wakeups ocorrer em casos tolas comosudo touch /dev/null
. É triste que parece não haver solução melhor ... Gostaria de saber qual seria o syscall certo para usar para implementar uma solução melhor.pause
, mas não é exposto diretamente a uma interface do shell.screen
, mas isso é para executar várias ocorrências do programa a partir de um script de shell para fins de teste, portanto, usarscreen
é um pouco exagerado.sleep infinity
é a solução mais clara que conheço.Você pode usar
infinity
porquesleep
aceita um número de ponto flutuante * , que pode ser decimal , hexadecimal , infinito ou NaN , de acordo comman strtod
.* Isso não faz parte do padrão POSIX, portanto não é tão portátil quanto
tail -f /dev/null
. No entanto, ele é suportado no GNU coreutils (Linux) e no BSD (usado no Mac) (aparentemente não suportado nas versões mais recentes do Mac - veja comentários).fonte
sleep infinity
também funciona em BSD e Mac .sleep infinity
aguarda no máximo 24 dias; quem esta certo?sleep
utilitário não está limitado a 24 dias ; é apenas o primeiro syscall que dorme por 24 dias e depois fará mais desses syscalls. Veja meu comentário aqui: stackoverflow.com/questions/2935183/…Sim,
2^31-1
é um número finito e não durará para sempre , mas darei $ 1000 quando o sono finalmente terminar. (Dica: um de nós estará morto até então.)fonte
sleep 2147483647d
...Você pode criar um binário que faça exatamente isso com:
fonte
Aqui está outra sugestão, usando os utilitários padrão do Unix, para "não fazer nada indefinidamente" .
Isso aciona um shell que é enviado imediatamente
SIGSTOP
, o que suspende o processo. Isso é usado como "entrada" para o seu programa. O complemento deSIGSTOP
éSIGCONT
, ou seja, se você sabe que o shell possui 12345 PID, podekill -CONT 12345
fazê-lo continuar.fonte
No Linux, você pode fazer:
No Linux, abrir / dev / fd / x onde x é um descritor de arquivo para a extremidade de gravação de um canal, fornece a extremidade de leitura do canal, então aqui é o mesmo que no stdin do programa. Então, basicamente,
read
nunca retornará, porque a única coisa que pode gravar nesse canal é ela mesma eread
não gera nada.Também funcionará no FreeBSD ou Solaris, mas por outro motivo. Lá, abrir / dev / fd / 1 fornece o mesmo recurso que abrir no fd 1, como você esperaria e como a maioria dos sistemas, exceto o Linux, o que significa que é o fim da escrita. No entanto, no FreeBSD e Solaris, os pipes são bidirecionais. Portanto, contanto
program
que não escreva em seu stdin (nenhum aplicativo faz), nãoread
haverá nada para ler nessa direção do pipe.Nos sistemas em que os pipes não são bidirecionais,
read
provavelmente ocorrerá um erro ao tentar ler um descritor de arquivo somente gravação. Observe também que nem todos os sistemas possuem/dev/fd/x
.fonte
x
bash; Além disso, com o zsh, você pode simplesmente fazerread
e funciona (embora eu não entenda o porquê!). Esse truque é específico do Linux ou funciona em todos os sistemas * nix?read
sozinho, ele lerá stdin. Portanto, se for o terminal, ele lerá o que você digitar até pressionar Enter.read
e funciona ?read | program > output
e funciona da mesma maneira que o que você sugeriu. (E eu não entendo o porquê.)A
read
solução de Stéphane Chazelas também funciona no Mac OS X se uma leitura fd for aberta/dev/fd/1
.Para poder matar
tail -f /dev/null
em um script (com o SIGINT, por exemplo), é necessário fazer o background dotail
comando ewait
.fonte
Redirecionar
/dev/zero
como entrada padrão!fonte