Enfileirar comandos enquanto um comando está sendo executado

Enfileirar comandos enquanto um comando está sendo executado

Suponha que você execute um comando que leva algum tempo para retornar e deseja executar um comando diferente depois de executado, mas não planejou isso com antecedência.

Eu sei que existe a opção de pressionar Ctrl + Ze enviar fg && otherCommand. No entanto, isso tem duas falhas principais:

  1. Não funciona se o primeiro comando for uma composição de comandos diferentes ( command1 && command2ou command1; command2) porque os comandos subsequentes da primeira linha enviada não serão executados.
  2. A execução do primeiro comando é interrompida enquanto você digita o próximo comando. Com esses comandos desagradáveis ​​de 30 segundos, o tempo que você gasta digitando o próximo comando representa uma boa parte do tempo de execução restante, se não todo.

Eu também sei que você pode simplesmente digitar o próximo comando enquanto um comando está sendo executado e clicar Enterpara executá-lo. No entanto, isso também tem duas falhas principais:

  1. Não funciona se o comando que você executa primeiro lê stdin.
  2. Se o comando executado primeiro produzir uma saída, você não poderá ver o que digitou.

Existe uma maneira rápida de enfileirar mais comandos enquanto um comando está sendo executado, possivelmente envolvendo o uso de um emulador de terminal especial ou de vários terminais?

Responder1

Pressione Ctrl+ Ze execute imediatamente bg. Isso faz com que o comando atual continue sendo executado em segundo plano. Então você pode usar fg && otherCommandpara agendar otherCommandapós o atual.

Para facilitar isso, configurei Ctrl+ Zno meu shell para executarbg quando pressiono-o em uma linha de comando vazia. VerNo zsh, como posso rejeitar mais rapidamente o processo em primeiro plano?eComo você envia aplicativos de linha de comando diretamente para segundo plano?; Não verifiquei se as versões modernas do bash facilitam fazer o mesmo.

Responder2

Você pode criar um pipe nomeado (isso precisa ser feito uma vez):

mkfifo ~/myfifo

Então, a partir de um terminal (vamos chamá-lo de terminal A), você pode dizer:

exec 10< ~/myfifo

Para atribuir a extremidade de leitura do pipe ao descritor de arquivo 10, você pode usar qualquer outro número acima de 2 (para que a entrada, saída e erro padrão permaneçam disponíveis se outro comando precisar).

Então, de outro terminal (vamos chamá-lo de terminal B), você pode dizer:

cat - > ~/myfifo

Para completar a conexão ao terminal A, que então retorna o prompt. Este comando grava o que você insere da entrada padrão no pipe. Então você pode inserir o seguinte no terminal A:

while read -u10 -r LINE; do eval "$LINE"; done

Portanto, ele executará os comandos digitados no terminal B. O readcomando lerá as linhas do descritor de arquivo 10 e executará com eval. evalpermite que você execute comandos shell, como exportar variáveis.

Enquanto o terminal A estiver aberto, você poderá interromper o loop com Ctrl + C para poder inserir comandos novamente e, posteriormente, reiniciar o loop para começar a executar os comandos restantes na fila.

Os comandos exec e while podem ser colocados em um shellscript para que você possa usar Ctrl-Z fg && yourscriptpara ativar o modo pipe caso tenha esquecido de fazê-lo no início.

Responder3

Você provavelmente deseja:

wait $pid

Se você não estiver executando no mesmo shell, não poderá usar um integrado e precisará de uma solução alternativa. Veja a discussãoaqui.

Responder4

EDITAR:Interpretei mal a pergunta, mas a técnica abaixo ainda pode ser útil para as pessoas ao executar comandos em um script bash (para que tenham um único PID)

Isto é o que eu uso (no Linux), quando o comando1 está imprimindo uma saída útil e eu só quero iniciar outro processo em outro shell assim que terminar (ou seja, não quero colocar o comando1 em segundo plano):

tail --pid=$command1_pid -f /dev/null; command2

onde $command1_pidestá o PID do processo que você está esperando terminar

(Acho que originalmente encontrei aqui:https://stackoverflow.com/a/41613532/1676393. Veja lá para outros detalhes úteis. Como uma versão que funcionará no Darwin (macOS))


Passo a passo:

  • pare o comando1 com Ctrl+Z
  • run ps, procure o processo correspondente ao comando1 e encontre seu PID
  • em seguida, reinicie o processo de command1 digitando fge, em um novo shell, execute o comando acima

Assim, o comando2 iniciará no novo shell quando o comando1 for executado no shell antigo.

informação relacionada