Как выполнить команду, не сохраняя её в истории (даже при нажатии клавиши “вверх”) в zsh

Вопрос или проблема

Люди упоминали о использовании хука preexec в zsh, но как именно мне его использовать? Я имею в виду, хорошо, я могу проверять каждую команду, является ли она той командой, которую я не хочу отображать в истории, но что делать после этого?

Это немного зависит от цели:

1. Просто избегание загромождения истории командами, которые вы не хотите запускать снова в какой-то момент

a) Скрытие всех команд

Запустите unset HISTFILE в вашей сессии оболочки, это отключит запись истории в файл. Хотя внутренняя история сессии будет продолжать работать, команды не будут сохранены в файл истории, и внутренняя история исчезнет, когда сессия будет закрыта.

b) Скрытие одиночных команд по запросу

Простой способ скрыть одиночные команды из истории в zsh — это включить HIST_IGNORE_SPACE (либо setopt HIST_IGNORE_SPACE, либо set -g подойдет). Когда это включено, любая команда, начинающаяся с пробела (или обычные псевдонимы, которые разворачиваются в команды, начинающиеся с пробела), будет удалена из истории.
Команда все еще будет отображаться при нажатии Up в подсказке после ее выполнения, но только если это последняя команда, и она не будет записана в файл истории. Выполнение любой другой команды также удалит ее из истории сессии (т.е. команда, начинающаяся с пробела, может быть вызвана с помощью Up только если она является последней командой, которая была выполнена).
Ее даже можно удалить из истории, не выполняя другую команду, просто введя один пробел и нажав Enter. Нажатие Up после этого покажет только команду, предшествующую команде, начинающейся с пробела.

c) Скрытие конкретных команд

Вы можете установить HISTORY_IGNORE на шаблон, который соответствует тем командам, которые вы не хотите фиксировать в истории. Например

HISTORY_IGNORE='(ls|cd /tmp/*)'

это предотвратит запись любой простой команды ls (без аргументов) и любой команды, начинающейся с cd /tmp/, в файл истории. Команды все еще будут полностью доступны в внутренней истории сессии. Если этого также не нужно, можно использовать хук zshaddhistory, чтобы расширить поведение и удалить ее оттуда с помощью

zshaddhistory () {
    emulate -L zsh
    [[ $1 != ${~HISTORY_IGNORE} ]]
}

(см. раздел о HISTORY_IGNORE в man zshparam и zshaddhistory в man zshmisc для более подробной информации)

2. Остановить определенные команды от препятствования другим предыдущим командам (т.е. уменьшить количество нажатий Up дважды)

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

Чтобы избежать этого, вы можете написать свой собственный виджет, чтобы обойти механизм истории.

sneaky-run () {   
    echo
    eval $BUFFER
    BUFFER=''
    zle reset-prompt
}

zle -N sneaky-run
bindkey '^X^M' sneaky-run

Этот виджет sneaky-run выполнит текущую введенную команду, затем очистит буфер команд и сбросит подсказку.
Команды, выполняемые внутри виджета, не добавляются в историю.

echo в начале необходим для того, чтобы вывод начинался с новой строки. Если у вас многострочная подсказка, вам может потребоваться добавить дополнительные echo для каждой дополнительной строки сразу перед zle reset-prompt, иначе подсказка может перезаписать несколько строк командного вывода.

В данном примере sneaky-run связан с комбинацией клавиш Ctrl+X, Enter.


Если вы не хотите использовать дополнительную комбинацию клавиш для этого, вы также можете обернуть виджет accept-line, который обычно связан с Enter

accept-line-with-sneaky () {   
    if [[ "$BUFFER" == "${BUFFER# }" ]] ; then
        zle accept-line
    else
        echo
        eval $BUFFER
        BUFFER=''
        zle reset-prompt
    fi
}

zle -N accept-line-with-sneaky
bindkey '^M' accept-line-with-sneaky

Это имитирует поведение настройки HIST_IGNORE_SPACE: Если команда начинается с пробела, она не будет добавлена в историю. Но, в отличие от HIST_IGNORE_SPACE, она также не будет доступна при нажатии Up.

Примечание: это переопределит одну из самых фундаментальных привязок клавиш zsh. Поэтому, пожалуйста, тщательно протестируйте это перед добавлением в ваш ~/.zshrc. Это также может работать не очень хорошо с встроенными командами оболочки, эффект которых может ограничиваться областью окружающей функции, например set, emulate и т.д..

Вам следует использовать опцию HIST_IGNORE_SPACE.

setopt HIST_IGNORE_SPACE

или установить ее в вашем профиле, а затем добавлять пробел перед командами, которые вы не хотите сохранять.

Ответ или решение

Чтобы выполнить команду в оболочке zsh без её сохранения в истории, в том числе для последовательного её извлечения с помощью клавиши «Вверх», вы можете воспользоваться несколькими методами. Ниже представлены подробные объяснения каждого из них.

1. Использование параметра HIST_IGNORE_SPACE

Самый простой способ скрыть отдельные команды из истории — это активировать опцию HIST_IGNORE_SPACE. При использовании этой опции команды, начинающиеся с пробела, не будут сохраняться в истории. Вот как это сделать:

setopt HIST_IGNORE_SPACE

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

 ls

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

2. Использование хука preexec

Если вы хотите избегать сохранения в истории определённых команд, вы можете воспользоваться хуком preexec. Этот хук срабатывает перед выполнением команды. Пример использования:

preexec() {
    if [[ "$1" == "ваша_команда" ]]; then
        # Убираем из истории
        HISTIGNORE="$HISTIGNORE $1"
    fi
}

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

3. Создание виджета для выполнения команд

Самым эффективным способом избежать какого-либо сохранения команд в истории является создание собственного виджета. Например, вы можете создать виджет sneaky-run, который будет выполнять введённую команду и очищать буфер команд:

sneaky-run() {   
    echo
    eval $BUFFER
    BUFFER=''
    zle reset-prompt
}

zle -N sneaky-run
bindkey '^X^M' sneaky-run

В данном примере мы привязываем виджет к сочетанию клавиш Ctrl + X, Enter. Используя этот виджет, команды будут выполняться, не добавляясь ни в внутреннюю, ни в внешнюю историю.

4. Оборачивание стандартной функции accept-line

Если вы хотите, чтобы команда не добавлялась в историю при нажатии клавиши «Enter», вы можете обернуть текстовую команду accept-line:

accept-line-with-sneaky() {   
    if [[ "$BUFFER" == "${BUFFER# }" ]] ; then
        zle accept-line
    else
        echo
        eval $BUFFER
        BUFFER=''
        zle reset-prompt
    fi
}

zle -N accept-line-with-sneaky
bindkey '^M' accept-line-with-sneaky

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

Заключение

Каждый из методов имеет свои преимущества и недостатки, и выбор зависит от ваших конкретных потребностей. Использование HIST_IGNORE_SPACE — самый простой способ, в то время как создание пользовательских виджетов позволит вам добиться большего контроля над историей команд. Не забудьте протестировать изменения в вашей конфигурации перед внесением окончательных правок в файл ~/.zshrc.

Оцените материал
Добавить комментарий

Капча загружается...