Зберігайте лише успішні команди в історії BASH


20

Іноді я неправильно розумію синтаксис команди:

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

Я повторюю спробу і все правильно:

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

Як я не дозволяю першій команді з кодом помилки, відмінним від 0, вводити історію?

Відповіді:


20

Я не думаю, що ти цього дуже хочеш. Мій звичайний робочий процес йде так:

  • Введіть команду
  • Виконати його
  • Зауважте, що це не вдається
  • Натисніть клавішу UP
  • Відредагуйте команду
  • Запустити його ще раз

Тепер, якщо невдала команда не була збережена в історію, я не міг би її легко повернути, щоб виправити та запустити знову.


3
Я думаю, що кращим дизайном була б історія сеансу та постійна історія. Спасибі!
Адам Матан

Історія зберігається під час виходу з терміналу. Отже, хоча ви можете повернутися до команд, які ви набрали в цьому сеансі терміналу, він фактично зберігається в історії баш при виході з терміналу.
Зробити

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.

Числа історії в In FAILED_COMMANDSповинні бути унікальними і відсортовані від найбільшого до найменшого, тому що при видаленні запису номери наступних команд зміщуються - тобто. коли ви видаєте history -d 2, 3-й запис стає другим, 4-й стає 3-м тощо.

Через це, використовуючи цей код, ви не можете вручну зателефонувати history -d <n>
там, де nменше або дорівнює найбільшій кількості, що зберігається,FAILED_COMMANDS
і очікувати, що код справно працює.

Це, ймовірно , хороша ідея , щоб зачепити exit_handlerна EXIT, але ви також можете зателефонувати в будь-який час його раніше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.