ksh93
tem disciplinas que normalmente são usadas para esse tipo de coisa. Com zsh
, você pode seqüestrar o recurso de diretório dinâmico nomeado :
Defina, por exemplo:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
E então você pode usar ~[incr]
para obter um incremento a $incr
cada vez:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Sua abordagem falha porque head -1 /tmp/ints
, head abre o fifo, lê um buffer completo, imprime uma linha e depois a fecha . Uma vez fechado, o final da escrita vê um cano quebrado.
Em vez disso, você pode:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ seq infinity > $fifo &
$ exec 3< $fifo
$ IFS= read -rneu3
1
$ IFS= read -rneu3
2
Lá, deixamos o final da leitura aberto no fd 3 e read
lê um byte de cada vez, não um buffer completo, para ter certeza de ler exatamente uma linha (até o caractere de nova linha).
Ou você pode fazer:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ while true; do echo $((++incr)) > $fifo; done &
$ cat $fifo
1
$ cat $fifo
2
Nesse momento, instanciamos um canal para cada valor. Isso permite retornar dados contendo qualquer número arbitrário de linhas.
No entanto, nesse caso, assim que cat
abre o fifo, o echo
loop é desbloqueado, para que mais echo
possa ser executado, quando cat
o conteúdo é lido e fechado o pipe (fazendo com que o próximo echo
instancie um novo pipe).
Uma echo
solução alternativa seria adicionar algum atraso, como por exemplo executando um externo como sugerido por @jimmij ou adicionar alguns sleep
, mas isso ainda não seria muito robusto, ou você poderia recriar o canal nomeado após cada um echo
:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Isso ainda deixa janelas curtas onde o canal não existe (entre o unlink()
done by rm
e o mknod()
done by mkfifo
) causando cat
falhas, e janelas muito curtas onde o pipe foi instanciado, mas nenhum processo será gravado novamente nele (entre o write()
e o close()
done by echo
) fazendo cat
com que não retorne nada e janelas curtas onde o pipe nomeado ainda existe, mas nada será aberto para gravação (entre o close()
done by echo
e o unlink()
done by rm
) em que cat
irá travar.
Você pode remover algumas dessas janelas fazendo o seguinte:
fifo=~/.generators/incr
(
umask 077
mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo &&
while
mkfifo $fifo.new &&
{
mv $fifo.new $fifo &&
echo $((++incr))
} > $fifo
do : nothing
done
) &
Dessa forma, o único problema é se você executar vários cat ao mesmo tempo (todos eles abrem o fifo antes que o nosso loop de gravação esteja pronto para abri-lo para gravação); nesse caso, eles compartilharão a echo
saída.
Eu também desaconselharia a criação de nomes fixos, fifos legíveis pelo mundo (ou qualquer arquivo para isso) em diretórios graváveis do mundo, a /tmp
menos que seja um serviço a ser exposto a todos os usuários no sistema.
command echo
ou em/bin/echo
vez de incorporadoecho
. Também - você pode fazer este comando um pouco mais curto:repeat 999 /bin/echo $((++incr)) > /tmp/int &
.Se você deseja executar o código sempre que o valor de uma variável for lido, não poderá fazer isso dentro do próprio zsh. A
RANDOM
variável (como outras variáveis especiais semelhantes) é codificada no código-fonte zsh. No entanto, você pode definir variáveis especiais semelhantes escrevendo um módulo em C. Muitos dos módulos padrão definem variáveis especiais.Você pode usar um co-processo para criar um gerador.
No entanto, isso é bastante limitado, porque você pode ter apenas um coprocesso. Outra maneira de obter progressivamente a saída de um processo é redirecionar de uma substituição de processo .
Observe que
head -1
não funciona aqui, porque lê um buffer inteiro, imprime o que gosta e sai. Os dados que foram lidos no canal permanecem lidos; essa é uma propriedade intrínseca dos pipes (você não pode inserir dados novamente). Oread
built-in evita esse problema lendo um byte de cada vez, o que permite que ele pare assim que encontrar a primeira nova linha, mas é muito lento (é claro que isso não importa se você está lendo apenas algumas centenas de bytes).fonte
bash
, consulte a seção bash nesse link.coproc
Coprocesses, quero dizer, queridos não zpty)coproc cmd1; exec 3>&p 4<&p; coproc cmd2 3>&- 4<&-...
Eu acho que faria isso com um sinal de algum tipo.
Isso funciona para mim de qualquer maneira.
Em uma nota apenas um pouco relacionada, aqui está algo estranho que eu descobri outro dia:
Também fica mais estranho:
fonte
bash
o comportamento tenha mudado? Eu acho que a afirmação depwd
não verificar e se referir apenas a$PWD
está incorreta.mkdir /tmp/dir; cd $_; PS4='$OLDPWD, $PWD + '; set -x; OLDPWD=$OLDPWD PWD=$PWD command eval ' cd ..; cd ..; cd ~; pwd'; pwd; cd .; pwd
pode mostrar o que eu quero dizer. É um problema que me incomodou com essans()
coisa.