Як я можу побачити точний командний рядок, який виконується в якомусь екземплярі bash?


29

У мене є тривалий bashекземпляр (всередині screenсеансу), який виконує складний набір команд всередині циклу (кожен цикл виконує труби, переадресації тощо).

Довгий командний рядок був написаний всередині терміналу - це не всередині жодного сценарію. Тепер я знаю ідентифікатор процесу bash, і у мене є доступ до кореня - як я можу побачити точний командний рядок, який виконується всередині цього bash?

Приклад
bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

І в іншому екземплярі оболонки я хочу бачити командний рядок, виконаний всередині 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'

Чи можливо це?

ЗРІД №1

Додавання зустрічних прикладів для деяких відповідей, які я отримав.

  1. Про використання функції cmdlineunder /proc/PID: це не працює, принаймні, не в моєму сценарії. Ось простий приклад:

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

    В іншій оболонці:

    $ cat /proc/8909/cmdline
    bash
    
  2. Використовувати ps -p PID --noheaders -o cmdтак само марно:

    $ ps -p 8909 --no-headers -o cmd
    bash
    
  3. ps -eaf також не корисно:

    $ 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
    

    Тобто, немає виводу з командного рядка ORIGINAL, який я шукаю - тобто while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done.

Відповіді:


40

Я знав, що хапаюся за соломку, але UNIX ніколи не виходить з ладу!

Ось як мені це вдалося:

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

Потім під (gdb)запитом я запустив команду, call write_history("/tmp/foo")яка запише цю історію у файл /tmp/foo.

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

Потім я відриваюся від процесу.

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

І киньте gdb.

(gdb) q

І досить впевнено ...

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

Для легкого подальшого використання я написав скрипт bash , автоматизуючи процес.


1
+1 дуже приємно прослуховування. Обов'язково позначте це як виключене A через 2 дні.
slm

@slm: Дякую! Я напишу про це в блозі - це було весело, охоплюючи це.
ttsiodras

1
З Readline включений , то ви також можете зробити це gdb: print (char *)rl_line_buffer. Поточна команда в послідовності є print (char *)the_printed_command. Ви також можете call history_builtin(), але це призведе до загальної кількості баш-процесу, тому це може бути менш корисним.
mr.spuratic

11
@slm: Не могла протистояти - я про це
блогував

1
Чи безпечна нитка bash? Вам доведеться сподіватися, що ви не змінюєте деякий внутрішній стан, який порушує поточний виконуваний код під час виконання чого-небудь з gdb. На практиці, bash майже напевно буде просто чекати, коли його дочірній процес закінчиться, коли трапляється призупинити його з gdb.
Адріан Пронк

5

Оскільки команда все ще виконується на екрані, її батьківський bash не перечитав жодної історії так:

  • повторно приєднати до екрана
  • натисніть ^Zпотімup arrow
  • бонус: загортайте команду в одиничні лапки (навігація з ^A^A- тому що екран (1) - і ^E) та echo + перенаправлення у файл
  • fg продовжувати виконання команд

Існують застереження, але це досить корисно, більшість часу.


Так, навіть вбиваючи це і натискаючи up. Хоча ви повинні бути впевнені, що він почнеться знову без проблем, але якщо цього не відбудеться, у вас все одно виникне та сама проблема після перезавантаження. Ви просто повинні вибрати свій момент, коли час простою не буде проблемою.
Матьє Наполі

0

Я знаю, що ти знайшов власну відповідь, але чи є причина, що ти не можеш зробити щось подібне:

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

Можливо, ви не можете поєднати результат фактичної роботи та вихід з bash, показуючи поточну лінію, що виконується.

Крім того , FWIW, якщо ви віддаєте перевагу багатослівність, set -o xtrace.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.