bash_history: закомментируйте опасные команды: `#`

16

Чтобы не регистрировать «опасные» команды в истории bash, я добавил в свой .bashrcфайл следующую строку :

HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'

это хорошо работает, но имеет побочный эффект: я не вижу полной истории команд, выполняемых на машине. Допустим, у меня есть несколько машин для экспериментов, и я хочу видеть все выполненные команды. Я бы использовал внутренний bash historyдля отображения выполненных команд и, возможно, grep для сегодняшней даты:

history | grep Sep-28

То, что я хотел бы сделать, - это также регистрировать «опасные» команды, но ставить #в начале строки, чтобы, если мне случится выполнить команду из истории по ошибке, никакого ущерба не будет.

Я понятия не имею, возможно ли это.

Обновление и уточнение:

Основная причина, по которой это является проблемой для меня, заключается в том, что я обычно подключаюсь к своей машине с нескольких терминалов, и любая команда, выполняемая на одном терминале, немедленно считывается в историю других терминалов. Это достигается

PROMPT_COMMAND="history -a; history -c; history -r"

Давайте представим, что у меня два открытых терминала. В одном у меня cat /dev/foo > file.outзапущен какой-то процесс. Во втором я проверяю прогресс с ls -lAhF. Я продолжаю повторять ls, нажимая Upи ENTER(то есть последнюю команду из истории). Как только первая команда заканчивается, последней команды из истории больше нет ls, но cat /dev/foo > file.out. Если я не буду осторожен, я начну cat снова и перезапишу file.out.

Я хотел бы добиться, чтобы команде cat предшествовала буква a #, чтобы она не выполнялась. Я, однако, все еще вижу это в истории и могу использовать его повторно (если это длинная команда), не комментируя его.

Мартин Вегтер
источник
Вместо того, чтобы повторять вашу команду вручную, вы можете использовать watch ls -lAhFили while sleep 1; do ls -lAhf; done; вместо просмотра размера файла вы можете использовать pv /dev/foo > file.out( ivarch.com/programs/pv.shtml ).
Deltab

Ответы:

9

Вы могли бы сделать что-то вроде:

fixhist() {
   local cmd histnum
   cmd=$(HISTTIMEFORMAT=/ history 1)
   histnum=$((${cmd%%[*/]*}))
   cmd=${cmd#*/} # remove the histnum
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -s "#$cmd"    # add back with a #
   esac
}
PROMPT_COMMAND=fixhist

Идея состоит в том, что перед каждым приглашением мы проверяем последнюю запись в истории ( history 1) и, если она является одной из опасных , мы удаляем ее ( history -d) и добавляем обратно с помощью #with history -s.

(очевидно, вам нужно удалить HISTIGNOREнастройки).

Нежелательный побочный эффект , что , однако, что он изменяет время истории тех rm, mv... команды.

Чтобы это исправить, альтернативой может быть:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
   esac
}
PROMPT_COMMAND=fixhist

На этот раз мы записываем время последней истории, и чтобы добавить обратно строку истории, мы используем history -rвременный файл (документ здесь), который включает метку времени.

Вы хотели бы, fixhistчтобы было выполнено перед вашим history -a; history -c; history -r. К сожалению, в текущей версии bashесть ошибка, history -aкоторая не сохраняет добавленную нами дополнительную строку. Обходной путь - написать вместо этого:

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
     (*)
       history -a
   esac
   history -c
   history -r
}
PROMPT_COMMAND=fixhist

То есть добавить комментируемую команду к HISTFILE самостоятельно, вместо того, чтобы позволить history -aей это сделать.

Стефан Шазелас
источник
не могли бы вы объяснить, что cmd=${cmd#*[0-9] }делает? И где именно я должен положить fixhistв мой PROMPT_COMMAND? На данный момент он уже содержитPROMPT_COMMAND="history -a; history -c; history -r"
Martin Vegter
какова роль HISTTIMEFORMAT=/? Я уже установил export HISTTIMEFORMAT="%b-%d %H:%M ". Кстати, когда я добавляю твой код в мой $HOME/.bashrc, ничего не происходит.
Мартин Вегтер
HISTTIMEFORMAT=/только для этого одного вызова, historyчтобы получить вывод, например, 123 /rm xгде легче извлечь cmd. Возникла проблема с некоторыми версиями того, bashгде $HISTCMDв этом контексте была фальшива, попробуйте новую версию.
Стефан Шазелас
все еще не работает. Мне интересно, #в коде не действуют как комментарии в .bashrc?
Мартин Вегтер
1
@MartinVegter, да, для измененных записей истории, bashвставляет *после номера истории, который не ожидался. Должно быть исправлено сейчас.
Стефан Шазелас
11

Я не собираюсь точно отвечать на ваш вопрос, но, возможно, дам вам альтернативное решение вашей проблемы.

Если я правильно понимаю, вы обеспокоены ошибками, которые вы могли бы совершить, набрав, например, !rmесли это случилось, что предыдущая rmкоманда в истории удаляет то, что вы хотели бы сохранить.

В этом случае хорошим вариантом bash является histverify. Если вы shopt -s histverify, и если вы вспомните команду с ударом !, она не будет выполнена немедленно, но будет загружена в readline, так что вы можете решить, выполнять ее или нет, и это также дает вам возможность редактировать ее.

Попытайся:

  • Без histverify:

    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    rm some_foo
    $ # oooops in fact I'd've like to keep it this time
  • С histverify:

    $ shopt -s histverify
    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    $ rm some_foo <cursor here>

    В этом случае у вас будет курсор в конце строки, готовый запустить его снова - или нет - или отредактировать.

Если вам нравится эта опция, поместите ее в .bashrc:

shopt -s histverify
gniourf_gniourf
источник