Иногда я неправильно понимаю синтаксис команды:
# mysql -d test
mysql: unknown option '-d'
# echo $?
2
Я пробую еще раз и получаю правильно:
# mysql --database test
Welcome to the MySQL monitor.
mysql >
...
Как предотвратить попадание в историю первой команды с кодом ошибки, отличным от 0?
решение1
Я не думаю, что вы действительно этого хотите. Мой обычный рабочий процесс выглядит так:
- Введите команду
- Запустить его
- Обратите внимание, что это не удается.
- Нажмите клавишу ВВЕРХ
- Изменить команду
- Запустите его снова
Теперь, если бы неудавшаяся команда не была сохранена в истории, я бы не смог легко ее исправить и запустить снова.
решение2
Единственный способ, который я могу придумать, — использовать history -d
in $PROMPT_COMMAND
. Проблема с этим или любым другим подходом заключается в том, что невозможно определить, завершилась ли команда с ошибкой или была успешно завершена с ненулевым кодом выхода.
$ grep non_existent_string from_file_that_exists
$ echo $?
1
решение3
Хорошо иметь последний неверный комментарий, чтобы его исправить, но вскоре после этого он превращается в потенциально запутанный мусор.
Мой подход состоит из двух этапов: сохранять команды, которые не выполняются, когда они происходят, и удалять их позже.
Сохраните команды, которые не выполняются, если они:
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
3-я запись становится 2-й, 4-я становится 3-й и т. д.
Из-за этого при использовании этого кода вы не можете вручную вызвать функцию history -d <n>
where, n
которая меньше или равна наибольшему числу, хранящемуся в,FAILED_COMMANDS
и ожидать, что код будет работать правильно.
Вероятно, хорошей идеей будет сделать звонок exit_handler
в EXIT
, но вы также можете позвонить в любое время раньше.