Como posso ver a linha de comando exata sendo executada dentro de alguma instância do bash?

29

Eu tenho uma instância bash longa (dentro de uma sessão screen ) que está executando um conjunto complexo de comandos dentro de um loop (com cada loop fazendo pipes, redirecionamentos, etc).

A longa linha de comando foi escrita dentro do terminal - não está dentro de nenhum script. Agora, conheço o ID do processo bash e tenho acesso root - como posso ver a linha de comando exata sendo executada dentro desse bash ?

Exemplo
bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

E em outra instância de shell, quero ver a linha de comando executada dentro do PID 1234:

bash$ echo $$
5678
bash$ su -
sh# cd /proc/1234
sh# # Do something here that will display the string  \
   'while true ; do someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done'

Isso é possível?

EDIT # 1

Adicionando contra-exemplos para algumas respostas que eu tenho.

  1. Sobre o uso do cmdline sob /proc/PID : isso não funciona, pelo menos não no meu cenário. Aqui está um exemplo simples:

    $ echo $$
    8909
    
    $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
    

    Em outro shell:

    $ cat /proc/8909/cmdline
    bash
    
  2. Usar ps -p PID --noheaders -o cmd é tão inútil:

    $ ps -p 8909 --no-headers -o cmd
    bash
    
  3. ps -eaf também não é útil:

    $ ps -eaf | grep 8909
    ttsiod    8909  8905  0 10:09 pts/0    00:00:00 bash
    ttsiod   30697  8909  0 10:22 pts/0    00:00:00 sleep 30
    ttsiod   31292 13928  0 10:23 pts/12   00:00:00 grep --color=auto 8909
    

    Ou seja, não há saída da linha de comando ORIGINAL, que é o que estou procurando - por exemplo, o while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done .

por ttsiodras 03.10.2014 / 08:58

3 respostas

40

Eu sabia que estava me agarrando ao canudo, mas o UNIX nunca falha!

Veja como eu consegui:

bash$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()

Em seguida, no prompt (gdb) , executei o comando call write_history("/tmp/foo") , que gravará esse histórico no arquivo /tmp/foo .

(gdb) call write_history("/tmp/foo")
$1 = 0

Eu então me separo do processo.

(gdb) detach
Detaching from program: /bin/bash, process 8909

e saia do gdb .

(gdb) q

E com certeza ...

bash$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

Para facilitar a reutilização futura, escrevi um script bash , automatizando o processo.

    
por 03.10.2014 / 10:13
5

Como o comando ainda está sendo executado na tela, seu bash pai não relerou nenhum histórico:

  • reconectar à tela
  • pressione ^Z , em seguida, up arrow
  • bônus: coloque o comando entre aspas simples (navegando com ^A^A - porque screen (1) - e ^E ) e eco + redirecionando para um arquivo
  • fg para prosseguir a execução do comando

Existem ressalvas, mas isso é útil o suficiente na maior parte do tempo.

    
por 04.10.2014 / 10:55
0

Eu sei que você encontrou sua própria resposta, mas há uma razão pela qual você não pode fazer algo assim:

(set -x; for f in 1 2 3 4 ; do  echo "$f"; sleep $f; done)

Talvez você não possa misturar a saída do trabalho real e a saída do bash mostrando a linha atualmente em execução.

Além disso, FWIW, se você preferir verbosidade, set -o xtrace .

    
por 07.10.2014 / 22:27