Это идеальный вариант использования ex
, рекомендованного POSIX инструмента для редактирования файлов.
(Если вы когда-либо использовали vi
, кстати, вы, вероятно, знакомы с ex
, поскольку все, что вы вводите в vi
, начинается с двоеточие :
- это команда ex
. ex
- это предшественник vi
.)
printf %s\\n 'g/NAME#AAAA/ /AGE/t- | s/^/#/ | /AGE/s/.*/AGE NIL/' x | ex input.txt
Если вы хотите протестировать его перед фактическим сохранением файла, измените последний x
перед символом вертикальной черты на % p
, и измененный файл не будет сохранен, но измененная версия будет напечатана на stdout
. Итак, вот тестовая команда:
printf %s\\n 'g/NAME#AAAA/ /AGE/t- | s/^/#/ | /AGE/s/.*/AGE NIL/' %p | ex input.txt
Объяснение:
printf% s \\ n
предоставляет простой способ передать несколько команд в ex
с новой строкой после каждой.
g / regex /
- глобальная команда; он запускает команды, которые следуют (до следующей новой строки) в каждой строке, соответствующей данному регулярному выражению.
/ AGE / t-
копирует следующую строку, которая соответствует шаблону / AGE /
, в позицию непосредственно перед текущей строкой (которая является строкой NAME # AAAA
). Он также перемещает курсор на новую копию строки (так что теперь она становится «текущей строкой»).
|
- разделитель команд в ex
.
s / ^ / # /
добавляет хэштег к скопированной строке AGE
. (Или знак фунта, в зависимости от вашего диалекта.);)
Следующая команда действительно состоит из двух частей: / AGE /
- это адрес, который заставляет эту команду работать со следующей строкой, содержащей это шаблон, а s /.*/ AGE NIL /
заменяет то, что было в этой строке, на AGE NIL
.
x
сохраняет изменения в файле и закрывается.
Отмена изменений
Чтобы отменить изменения, я бы сделал следующее:
printf %s\\n 'g/NAME#AAAA/ ?^#AGE? m /^AGE/ | s/^#// | -d' %p | ex input.txt
Затем, когда изменение было подтверждено, фактически сохраните изменения с помощью:
printf %s\\n 'g/NAME#AAAA/ ?^#AGE? m /^AGE/ | s/^#// | -d' x | ex input.txt
Объяснение:
Глобальная команда, как и раньше.
Возьмите строку, которая начинается с #AGE
перед строкой NAME, переместите ее после следующей строки, которая начинается с AGE
.
Удалите ведущий #
.
Удалите непосредственно предшествующую строку с помощью -d
(которая является линией возраста NIL).
Распечатать или сохранить изменения.
Вы можете указать несколько дескрипторов файлов для peekfd
.
например,
peekfd -n -8 -d -c 24184 0 1 2
будет искать на stdin, stdout и stderr pid 24184.
Опция -c
также присоединится к любым дочерним процессам. Это необходимо для того, чтобы увидеть вывод от них (например. увидеть вывод ls
, который был запущен в подглядываемом shell-процессе)
Странно, но я обнаружил, что она всегда успешно присоединяется к дочернему процессу (независимо от того, какой дочерний процесс я запускаю в подглядываемом tty - ls
, uname
, /bin/echo
в отличие от встроенного echo
), но также всегда выводит сообщение об ошибке Error attaching to pid -38
(а "pid" - это всегда -38).
man peekfd
говорит:
ДИАГНОСТИКА
На stderr может быть выдана следующая диагностика:
Error attaching to pid ...
Произошла неизвестная ошибка при попытке присоединения к процессу... возможно, вам понадобится root.
Похоже на ошибку - я запускаю peekfd
от имени root, и он всегда выводит сообщение об ошибке, всегда с одним и тем же фальшивым (-38
) PID.
ОСТОРОЖНО: на странице руководства также написано:
BUGS
Возможно, много. Не удивляйтесь, если процесс, за которым вы следите, умрет.
SystemTap
3 строчки, проблема решена, SystemTap полностью рулит:
Установить SystemTap, создать ptysnoop файл:
#!/usr/bin/stap
probe kernel.function("pty_write") {
if (kernel_string($tty->name) == @1) {
printf("%s", kernel_string_n($buf, $c))
}
}
Сделать его исполняемым. Теперь для просмотра /dev/pts/6
достаточно:
$ sudo ptysnoop pts6
Edit: other solutions found earlier
ttyrpld выглядит довольно солидно:
ttyrpld - это многоосный tty-логгер на уровне ядра (key и screenlogger для ttys) с поддержкой (a)synchronous replay. Он поддерживает большинство типов tty, включая vc, bsd и unix98-стиль ptys (xterm/ssh), serial, isdn и т.д. Реализация в ядре делает его неизбежным для пользователя по умолчанию. Он работает без накладных расходов, если демон протоколирования не активен.
Однако для этого нужен модуль ядра.
Я закончил писать небольшой инструмент ttylogger на основе strace, который хорошо работает для моих нужд. Все, что вам нужно, это perl и strace:
$ sudo ttylogger pid
Используйте это с pid пользовательской оболочки для дампа вывода всех последующих команд.
readme для подробностей.