Início do bloqueio do terminal

5

Se você digitar este comando de teste simples:

gnome-terminal -x bash -c "ls;sleep 3"

Você verá que ele retorna imediatamente (o terminal recém-criado, naturalmente, permanece por três segundos). Isso está em contraste com, digamos, rxvt (mesmo comando, mas com e ).

Se você quiser um início de bloqueio, o consenso histórico parece ter sido para usar --disable-factory . Infelizmente, isso não funciona mais (testado 3.14.2).

Então, como faço para iniciar o terminal de maneira não assíncrona?

Bônus: konsole , lxterminal e xfce4-terminal também têm o mesmo problema. Comandos para aqueles?

    
por imallett 22.05.2015 / 16:38

5 respostas

4

Eu uso um método que tem algumas semelhanças com a resposta de terdon (e foi criado com alguma ajuda dele - Obrigado @terdon por isso!), mas tem uma abordagem um pouco diferente:

Eu crio um arquivo temporário para que o terminal filho possa se comunicar com o terminal pai e informar o PID de sua instância bash correspondente. Então deixo o terminal pai ler o arquivo temporário e lembro do PID, excluo o arquivo e continuo verificando a cada 100ms (o atraso pode ser alterado) se a instância do bash do terminal filho ainda está em execução. Caso contrário, o terminal foi fechado manualmente ou porque o comando foi concluído. Em seguida, o comando de inicialização termina e o terminal pai é utilizável novamente.

Vantagem dessa abordagem:
Todos os comandos que serão lançados ( ls; sleep 3 ou qualquer substituto para aqueles) são executados após o comando que é responsável por permitir a detecção do fechamento do terminal. Portanto, se o comando interno trava ou você fecha o terminal manualmente antes de terminar, o mecanismo ainda está funcionando e continuará a execução do script externo em vez de executar em loops infinitos.

O código como one-liner com saída de depuração ("lançado" depois que a janela do terminal filho foi aberta, "terminado" depois que foi fechado) e a precisão de 0.1 segundos é:

pidfile=$(mktemp); gnome-terminal -x bash -c "echo $$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; echo "launched"; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done; echo "terminated"

Ou sem saída de depuração:

pidfile=$(mktemp); gnome-terminal -x bash -c "echo $$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done

Quase o mesmo código, mas com mais flexibilidade, escrito como script bash:

#! /bin/bash

delay=0.1
pidfile=$(mktemp)

gnome-terminal -x bash -c "echo $$>$pidfile; ls; sleep 3"

until [ -s $pidfile ] 
    do sleep $delay
done
terminalpid=$(cat "$pidfile")
rm $pidfile
echo "launched"
while ps -p $terminalpid > /dev/null 2>&1
    do sleep $delay
done
echo "terminated"

Você pode omitir as linhas echo "launched" e echo "terminated" , claro, assim como você pode alterar a linha delay=0.1 para outro atraso entre duas verificações do estado do terminal (em segundos) se você precisar que seja mais ou menos preciso.

Para executar outro comando personalizado no terminal filho, substitua a linha

gnome-terminal -x bash -c "echo $$>$pidfile; ls; sleep 3"

com o seguinte (insira seu comando em vez do marcador de posição maiúsculo!)

gnome-terminal -x bash -c "echo $$>$pidfile; INSERTYOURCOMMANDSHERE"
    
por Byte Commander 22.05.2015 / 20:28
3

Os mantenedores do Ubuntu do pacote gnome-terminal notaram este problema e criaram um script wrapper (no pacote Ubuntu gnome-terminal-3.14.2-0ubuntu3 ) para reabilitar a opção --disable-factory ; no entanto, o script wrapper não funciona!

Do changelog link :

  

gnome-terminal (3.14.2-0ubuntu3) vivid; urgência = médio

     
  • debian / gnome-terminal: Adicione um script wrapper para iniciar o gnome-terminal com   um id de aplicativo diferente quando um usuário passa o agora ignorado --disable-factory   opção. Isso deve restaurar a compatibilidade com lançadores antigos para usuários que   estão atualizando.   [...]
  •   

Eu não consigo navegar no Ubuntu "Launchpad" (muito pelo código aberto), mas o script wrapper pode ser encontrado em link (chamado gnome-terminal.wrap ).

O erro é que o script gnome-terminal.wrap está aguardando o processo filho errado; ele deve estar aguardando no servidor de terminal, não no cliente do terminal. A correção é alterar os dois métodos server_appeared e spawn_terminal_server da seguinte maneira:

    def server_appeared(self, con, name, owner):
        # start gnome-terminal now
        gt = Gio.Subprocess.new(['/usr/bin/gnome-terminal.real',
                                 '--app-id', name] +
                                self.args,
                                Gio.SubprocessFlags.NONE)
        # removed a line here: gt.wait_async(...)

    def spawn_terminal_server(self, name):
        ts = Gio.Subprocess.new(['/usr/lib/gnome-terminal/gnome-terminal-server',
                                 '--app-id',
                                 name],
                                Gio.SubprocessFlags.NONE)
        ts.wait_async(None, self.exit_loop, ts)

Você pode fazer o download do arquivo corrigido de: link .

Eu notifiquei o mantenedor do pacote, então espero que ele seja corrigido em breve.

Outro fato interessante: o gnome-terminal pode ser construído com um cliente alternativo chamado gterminal , que possui uma opção --wait que parece fazer exatamente o que você deseja. No entanto, infelizmente o Ubuntu não o constrói ou instala em seu pacote gnome-terminal.

    
por ecatmur 22.05.2015 / 21:15
3

Em sua infinita sabedoria, os desenvolvedores do GNOME decidiram remover essa opção. Infelizmente, sua sabedoria não se estendeu a atualizar também sua página man , que ainda a lista. Assim, parece que gnome-terminal será sempre executado em segundo plano e a sessão de shell pai será retornada imediatamente. Para contornar isso, você tem algumas opções:

  1. Use apenas outro terminal. Eu tentei com xterm, rxvt e GNOME terminator, tudo funcionou como esperado.

  2. Use alguns hacks feios. gnome-terminal , quando executado pela primeira vez, lança /usr/lib/gnome-terminal/gnome-terminal-server . Por alguma razão, isso significa que o processo é concluído assim que você o inicia. Para ilustrar:

    $ gnome-terminal  -x sh -c "ls;sleep 30" 
    [1] 5896
    $ jobs
    [1]+  Done                    gnome-terminal -x sh -c "ls;sleep 30"
    

    Como você pode ver acima, depois de iniciá-lo em segundo plano, o trabalho iniciado sai imediatamente. Isso significa que meu primeiro pensamento de lançá-lo em segundo plano e usar $! para verificar se ele ainda está em execução não funcionará. Isso significa que você terá que fazer algo menos elegante, como criar um arquivo:

    tmpfile=$(mktemp); gnome-terminal  -x sh -c "ls;sleep 30; rm $tmpfile" 
    while [ -e $tmpfile ] ; do :; done
    

    Os comandos acima irão i) criar um arquivo temporário ( tmpfile=$(mktemp) ); ii) iniciar o gnome-terminal, dizendo para deletar $tmpfile quando terminar e iii) não fazer nada ( : ) enquanto o arquivo temp existir while [ -e $tmpfile ] . Isso resultará em um terminal que aguarda até que o processo seja executado por gnome-terminal tenha terminado antes de continuar.

por terdon 22.05.2015 / 18:13
0

Eu tenho usado o gnome-terminal mais novo, e o comportamento que você descreveu para o gnome-terminal parece ser o mesmo para o konsole, lxterm e rxvt (tentei todos os 3). Então, como o OP não respondeu a nenhum comentário até o momento para esclarecer o que ele quer, estou assumindo que o OP deseja continuar usando o terminal pai sem esperar que o terminal filho termine.

Isso pode ser alcançado com gnome-terminal & . Se você quiser evitar que o terminal filho seja fechado quando o pai sair, use nohup gnome-terminal & . Para evitar a exibição de erros no terminal pai, use gnome-terminal 2> /dev/null & ou nohup gnome-terminal 2> /dev/null & .

    
por Sergiy Kolodyazhnyy 22.05.2015 / 18:16
0

Para pessoas em fevereiro de 2017 & lt; t & lt; Março de 2018, que veio a este site via google, a solução simples é:

gnome-terminal --disable-factory -e "cmd"

funciona e inicia o gnome-terminal de maneira síncrona / bloqueante como esperado.

Testado em:

  • Ubuntu 16.04
  • gnome-terminal 3.18.3
por Oscillon 19.02.2017 / 18:28