Сохраняйте только успешные команды в истории BASH

20

Иногда я неправильно понимаю синтаксис команды:

# mysql -d test
mysql: unknown option '-d'
# echo $?
2

Я пытаюсь снова и понимаю это правильно:

# mysql --database test
Welcome to the MySQL monitor.
mysql >
...

Как запретить первой команде с кодом ошибки, отличным от 0, войти в историю?

Адам Матан
источник

Ответы:

20

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

  • Введите команду
  • Запустить его
  • Заметьте, что это не удалось
  • Нажмите клавишу ВВЕРХ
  • Редактировать команду
  • Запустите это снова

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

Рене Саарсоо
источник
3
Я думаю, что лучшим дизайном будет история сессий и постоянная история. Благодарность!
Адам Матан
История сохраняется при выходе из терминала. Таким образом, хотя вы можете вернуться к командам, которые вы ввели в этом терминальном сеансе, он фактически сохраняется в истории bash при выходе из терминала.
Сделать
11

Единственный способ , которым я могу думать , чтобы сделать это было бы использовать history -dв $PROMPT_COMMAND. Проблема этого или любого другого подхода заключается в том, что невозможно определить, была ли команда завершена с ошибкой или успешно завершена с ненулевым кодом завершения.

$ grep non_existent_string from_file_that_exists
$ echo $?
1
Приостановлено до дальнейшего уведомления.
источник
4

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

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

Сохраните команды, которые терпят неудачу, когда они делают:

error_handler() {
    FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}

trap error_handler ERR

trap command signalsвыполняется, commandкогда один из signals"поднят".

$(command), выполняет commandи захватывает его вывод.

При сбое команды этот фрагмент кода фиксирует номер истории последней команды, сохраненной в истории , и сохраняет ее в переменной для последующего удаления.

Простой, но работает неправильно с HISTCONTROLи HISTIGNORE- когда команда не сохраняется в истории из-за одной из переменных, номер истории последней команды, сохраненной в истории, равен номеру предыдущей команды; поэтому, если неправильная команда не сохранена в истории, предыдущая команда будет удалена.

Чуть более сложная версия, которая корректно работает в таком случае:

debug_handler() {
    LAST_COMMAND=$BASH_COMMAND;
}

error_handler() {
    local LAST_HISTORY_ENTRY=$(history | tail -1l)

    # if last command is in history (HISTCONTROL, HISTIGNORE)...
    if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
    then
        # ...prepend it's history number into FAILED_COMMANDS,
        # marking the command for deletion.
        FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
    fi
}

trap error_handler ERR
trap debug_handler DEBUG

Удалить сохраненные команды через некоторое время:

exit_handler() {
    for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
    do
        history -d $i
    done
    FAILED_COMMANDS=
}

trap exit_handler EXIT

Объяснение:

При выходе из Bash для каждого уникального номера истории удаляйте соответствующую запись истории,
затем снимите флажок, FAILED_COMMANDSчтобы не удалять команды, унаследовавшие номера истории от уже удаленных команд.

Если вы уверены, что в нем FAILED_COMMANDSне будет дубликатов, вы можете просто перебрать его
(т.е. записать for i in $FAILED_COMMANDS). Однако, если вы ожидаете, что он не будет отсортирован от наибольшего к наименьшему (в данном случае это всегда так), замените его uniqна sort -rnu.

Номера истории в FAILED_COMMANDSдолжны быть уникальными и сортироваться от наибольшего к наименьшему, потому что при удалении записи номера следующих команд смещаются, т.е. при выдаче history -d 2третья запись становится второй, четвертая становится третьей и т. д.

Из-за этого при использовании этого кода вы не можете вручную вызвать, history -d <n>
где nменьше или равно наибольшему числу, хранящемуся в,FAILED_COMMANDS
и ожидать, что код будет работать должным образом.

Это, вероятно , хорошая идея , чтобы зацепить exit_handlerна EXIT, но вы также можете позвонить в любое время его раньше.

GingerPlusPlus
источник