Como você implementa a substituição do processo (usando um script bash) em um shell que não o possui?

3

Eu vi o shell do Fish implementar a substituição do processo como uma função:

# === Fish shell lang:
function psub
   mkfifo $the_pipe
   cat >$the_pipe &
   echo $the_pipe
   # remove pipe when bg job is done
end  

# Example:
diff (echo abc | psub)  (echo def | psub)

Código completo: link

Eu tentei por várias horas reimplementá-lo para um shell não-Fish (mksh), mas não consegui:

# Executable file:  my.psub.sh
the_pipe="$(mktemp /tmp/pipe.XXXXXXXXXX)"
mkfifo $the_pipe
cat >$the_pipe &
echo $the_pipe

# Example:
diff $(echo abc | my.psub.sh)  $(echo def | my.psub.sh)

Os blocos de comando. Eu tentei tudo o que pude pensar, mas não tenho a menor idéia de para onde ir em seguida.

    
por dgo.a 29.03.2016 / 13:44

2 respostas

2

É um pouco difícil, mas factível:

function die {
        print -ru2 -- "E: $*"
        exit 1
}

function psubin {
        local stdin=$(cat; echo .) pipe

        pipe=$(mktemp /tmp/psub.XXXXXXXXXX) || die mktemp

        # this is racy
        rm -f "$pipe"
        mkfifo "$pipe" || die mkfifo

        (
                # don’t block parent
                exec <&- >&- 2>&-
                # write content to FIFO
                print -nr -- "${stdin%.}" >"$pipe"
                # signal EOF to reader, ensure it’s not merged
                sleep 0.1
                :>"$pipe"
                # clean up
                (sleep 1; rm -f "$pipe") &
        ) &
        print -nr -- "$pipe"
}

diff -u $(echo abc | psubin) $(echo def | psubin)

Os problemas que você e eu encontramos aqui são:

  • mkfifo reclama, a menos que você produza primeiro rm mktemp
  • blocos mksh para o processo em segundo plano se ainda compartilhar quaisquer descritores de arquivo (stdin, stdout, stderr) com o pai (Nota: Esse provavelmente é o único caso de uso válido para usar >&- em vez de >/dev/null e porque podemos garantir que esses fds não sejam mais usados, nem substituídos por novos fds)
  • como não temos stdin no processo em segundo plano, precisaremos armazenar em cache seu conteúdo, exatamente
  • EOF com FIFOs (pipes nomeados) não é trivial. Vamos apenas deixar isso em diante ... (poderíamos fazer alguns truques ao tentar abrir o non-blocking FIFO para verificar se há um leitor e sinalizar EOF até o leitor morrer, mas isso funciona bem por enquanto )
  • é melhor se o FIFO for removido após o uso…

Por outro lado: bom que estamos fazendo isso agora, porque eu eventualmente pretendo implementar o <(…) no mksh, e então eu preciso saber o que observar, já que não podemos usar /dev/fd/ como faz o GNU bash, porque não é portátil o suficiente.

    
por 30.03.2016 / 22:09
-1

Isso não parece possível:

 diff   (echo abc | ./my.psub.sh)    (echo def | ./my.psub.sh)

Bloqueia quando as duas sub-shells precisam sair antes que diff seja executado.

É factível no shell Fish, mas muito provavelmente porque eles fazem coisas como substituição de comandos e processos muito diferente com seu próprio conjunto de problemas .

Uma alternativa seria usar busybox como sugerido em " Solução alternativa para substituição de processos em mksh ":

busybox diff =(sort ./a) =(sort ./b)
    
por 13.04.2017 / 14:18