Назад | Перейти на главную страницу

Как получить историю bash или последние x числовых строк из процесса оболочки, запущенного на другом tty

интересная дилемма. Это Centos. Вчера вечером я вошел в физическую консоль на tty. Я запустил команду и позволил ей работать всю ночь. Терминал по-прежнему находится в системе, но в настоящее время я удаленно авторизован через ssh (меня нет на консоли).

Я хотел бы знать точные параметры команды, которые я использовал (я не помню), поэтому я хотел бы увидеть команду, которую я выполнял на этом терминале. Поскольку оболочка все еще работает, она ничего не записала в bash_history - история этого экземпляра все еще находится в памяти.

Итак, мой вопрос в том, есть ли способ удаленно получить то, что я хочу, возможно:

(a) отправка сигнала запущенной оболочке, заставляющая ее сбрасывать свою историю bash (b) изучение среды запущенной оболочки для получения информации о ее истории (c) проверка последних x # строк из сеанса tty, чтобы Я вижу, что я напечатал

или каким-то другим способом ....

Хорошо, я разобрался. На самом деле это довольно изящная вещь, поскольку я предвижу, что она найдет множество применений.

  1. открыть сеанс ssh на удаленном хосте. запустить сеанс экрана или tmux с несколькими окнами. Вы можете определить псевдоустройство для каждого окна, набрав «tty». Допустим, у нас есть «/ dev / pts / [123]», соответствующий трем оболочкам, которые мы запускаем в сеансе экрана.

  2. определить pid рассматриваемого процесса bash (того, для которого вы хотите перенаправить ввод и вывод). этот процесс в настоящее время связан с терминальным устройством, таким как / dev / tty1

  3. из окна экрана 1 запустите «gdb -p [pid]» и выполните следующие команды в gdb:

    а. p dup2 (open ("/ dev / pts / 2", 0), 0) # это изменяет стандартный ввод для целевого процесса

    б. p dup2 (open ("/ dev / pts / 3", 1), 1) # это изменяет стандартный вывод для целевого процесса

    c. p dup2 (open ("/ dev / pts / 3", 1,), 2) # это изменяет стандартную ошибку для целевого процесса

    d. отделить

    е. уволиться

Другими словами, шаг 3 делает Окно 2 стандартным вводом, а Окно 3 выводом.

4. из окна 1 (/ dev / pts / 1) «ls -l / proc / [pid] / fd», чтобы проверить изменения файлового дескриптора для процесса bash, которым мы хотим управлять

5. то, что вы вводите в окне 2, теперь передается в два места: исходная оболочка bash, связанная с этим окном, и целевой процесс. поэтому в окне 2 (/ dev / pts / 2) введите «hhiissttoorryy [return] [return]». Причина, по которой вы должны вводить все дважды, заключается в том, что входные данные делятся как на текущую оболочку bash, так и на целевую оболочку bash. Это потому, что операционная система знает, что есть два источника, которые используют ввод с клавиатуры для / dev / pts / 2, и справедливо распределяет символы, которые вы вводите. первый символ переходит к одному месту назначения, следующий - ко второму месту назначения и т. д. Если у вас было три процесса, чей стандартный ввод был / dev / pts / 3, то вам пришлось бы вводить каждый символ по три раза. Ядро передает входящие символы получателям циклически.

6. Вы можете обойти вышеуказанное неудобство, временно установив stdin для исходной оболочки Window 2 bash на какое-либо неиспользуемое устройство, например / dev / tty5 или что-то в этом роде. это делает клавиатуру / dev / pts / 2 стандартным вводом только для одного процесса (вместо двух). теперь вы можете вводить команды как обычно (они просто не будут отображаться на экране, в котором вы находитесь, вместо этого они будут отображаться в / dev / pts / 3).

7. так как вы набрали «история» и она была передана целевому процессу, стандартный вывод которого - окно 3, переключитесь в окно 3, чтобы вы могли видеть вывод команды. теперь у вас есть история команд для целевой оболочки bash.

8. вернувшись в окно 1, снова используйте gdb на [pid], чтобы сбросить стандартные значения in, out, err для целевой оболочки обратно к их исходным значениям (/ dev / tty1). И вы также можете вернуть стандартный ввод Window 2 на то, что должно быть.

  1. Если хотите, вы можете очистить лишние файловые дескрипторы, удалив их с помощью 'exec 3> & -', например, чтобы удалить fd 3.

Обратите внимание, что когда вы запускаете gdb в запущенном процессе, он приостанавливает выполнение процесса так же, как и SIGSTOP. Когда вы его «отсоединяете», он возобновляет работу, как в SIGCONT. Это позволяет манипулировать дескрипторами файлов без неблагоприятных последствий.

Я не пробовал, но вы, вероятно, можете сделать описанное выше еще проще и удобнее, открыв оболочку, определив ее tty или pty, временно установив назначенный стандарт оболочки для неиспользуемого устройства, назначив tty / pty как стандартный ввод / вывод для целевой оболочки. Таким образом, вы можете использовать один экран для всего ввода и вывода с целевой оболочкой.

РЕЗЮМЕ: с помощью описанной выше процедуры, если у вас есть оболочка, к которой у вас есть доступ, вы можете использовать ее в качестве стандартного входа / выхода для любого другого процесса / оболочки в системе. Это полезно, например, если вы хотите взаимодействовать с оболочкой, запущенной на консоли, но у вас нет физического доступа к хосту (или решения для отключения света). Это, конечно, можно обобщить на любое количество ситуаций, когда вы хотите, чтобы конкретная оболочка контролировала ввод / вывод для любого процесса по вашему выбору.

Я до сих пор сталкиваюсь с этой ситуацией полурегулярно и, наконец, придумал несколько более простых способов восстановления команд истории в памяти из моих "осиротевших" сеансов bash:

(примечание: в каждом примере ниже замените PID с идентификатором процесса осиротевшего сеанса bash)

Эффективно запускать history -a:

$ gdb -p PID -batch -ex 'call maybe_append_history(get_string_value("HISTFILE"))'

Выгрузите последние 10 записей истории в локальный терминал (pty)

$ gdb -p PID -batch -ex 'call append_history(10, "'$(tty)'")'

Сделайте резервную копию всей истории во временный файл:

$ gdb -p PID -batch -ex 'call write_history("/tmp/history-backup.txt")'

Ноты:

  • Протестировано с помощью bash 4.3 в Ubuntu 16.04.01.
  • В моей системе мне пришлось вызывать, используя sudo gdb - даже для доступа к моим собственным процессам bash.
  • Если вызов прошел успешно, вы должны увидеть $1 = 0 (если вы видите другие значения, они, вероятно, errno's - например, при попытке добавить в файл, который еще не существует, вы получите $1 = 2 (ENOENT)).
  • Этот подход основан на изучении того, что код bash C делает в ответ на history команда; например: builtins / history.def # L203-L212

Вы можете получить эту информацию из /proc/${PID}/cmdline.