Ctrl X-E без немедленного выполнения команды

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

Очень удобно, что вы можете вводить сложные команды в $EDITOR (vim в моем случае) с помощью Ctrl XE в Bash.

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

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

# в Bash

_edit_wo_executing() {
    local editor="${EDITOR:-nano}"
    tmpf="$(mktemp)"
    printf '%s\n' "$READLINE_LINE" > "$tmpf"
    "$editor" "$tmpf"
    READLINE_LINE="$(<"$tmpf")"
    READLINE_POINT="${#READLINE_LINE}"
    rm -f "$tmpf"  # -f для тех, у кого есть alias rm='rm -i'
}

bind -x '"\C-x\C-e":_edit_wo_executing'

Теперь Ctrl xe должно делать то, что вы хотите.

Примечания:

  • Я использовал только базовую логику для установки editor; отрегулируйте это под свои нужды.

  • READLINE_POINT="${#READLINE_LINE}" должен помещать курсор в самое конец. Bash 5 ожидает длину в символах, и приведенный выше код работает; но Bash 4 ожидает байты. Чтобы обрабатывать не-ASCII текст в Bash 4, используйте

    READLINE_POINT="$(printf '%s' "$READLINE_LINE" | wc -c)"
    

    (Я узнал из этого ответа).

  • При нажатии клавиши функция выполняется в вашей текущей оболочке, поэтому (в отличие от сценария) ваши алиасы будут работать. -f в rm -f был предложен пользователем, который использует alias rm='rm -i'. В общем, вы можете захотеть выполнить неалиасированный rm.

Хотя это не прямо отвечает на ваш вопрос, в следующих оболочках поведение, которое вы запросили, подтверждено как стандартное:

  • Zsh
  • Fish
  • Nushell

В этих (и, безусловно, других) оболочках закрытие редактора вставит буфер редактора в текущую командную строку без его выполнения.

У меня возникла проблема с ответом Камила. Та же проблема, о которой комментировал Леви, что bash выполняет только первое слово, но исправление, предложенное Себастьяном Карлосом, не сработало для меня. Для меня проблема заключалась в перенаправлении из временного файла в переменную readline READLINE_LINE="$(<"$tmpf")".

Я исправил это, заменив перенаправление на cat

_edit_wo_executing() {
    local editor="${EDITOR:-nvim}"
    tmpf="$(mktemp)"
    printf '%s\n' "$READLINE_LINE" > "$tmpf"
    "$editor" "$tmpf"
    READLINE_LINE="$(cat "$tmpf")"
    READLINE_POINT="${#READLINE_LINE}"
    \rm -f "$tmpf"  # -f для тех, у кого есть alias rm='rm -i'
}

в в этой похожей теме, @karlicoss демонстрирует, как выйти из vim с ненулевым кодом выхода, что заставит Readline не выполнять команду, даже если :w уже было выполнено. Я не осмеливаюсь повторять 3-байтовое решение из страха быть покараным администраторами за плагиат.

редактировать: Это не объясняет, как вывести из редактора в текущую строку в readline, но объясняет, как “ctrl x+E не выполняя команду немедленно”, что и привело меня к этой теме.

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

Вопрос, который вы задали, касается возможности редактирования команд в Bash через редактор, не выполняя их немедленно. Ниже представлены подробные пояснения и решение, которое может помочь вам достичь этой цели.

Использование редактора в комбинации с Bash

По умолчанию в Bash, когда вы используете комбинацию клавиш Ctrl + X, Ctrl + E, команда, которую вы написали, выполняется сразу же после закрытия редактора (например, vim). Однако, если вам необходимо сначала отредактировать команду, а затем вставить её в командную строку без выполнения, это можно реализовать с помощью создания функции в Bash.

Решение: Не выполнять команду немедленно

Вот пример простой функции, которая позволит вам редактировать команду в редакторе и вставить её обратно в командную строку:

_edit_wo_executing() {
    local editor="${EDITOR:-nano}"  # Используйте редактор, заданный в переменной окружения, в противном случае - nano
    tmpf="$(mktemp)"                 # Создайте временный файл
    printf '%s\n' "$READLINE_LINE" > "$tmpf"  # Запишите текущее содержимое строки командной строки в временный файл
    "$editor" "$tmpf"                # Откройте временный файл в редакторе
    READLINE_LINE="$(cat "$tmpf")"  # Поместите содержимое временного файла обратно в переменную READLINE_LINE
    READLINE_POINT="${#READLINE_LINE}"  # Установите курсор в конец строки
    \rm -f "$tmpf"                   # Удалите временный файл
}

bind -x '"\C-x\C-e":_edit_wo_executing'  # Привязка функции к комбинации клавиш Ctrl + X, Ctrl + E

Пояснения к коду

  1. Редактор по умолчанию: В коде используется переменная EDITOR, чтобы определить, какой редактор будет использоваться. Если переменная не установлена, будет использоваться nano.

  2. Временный файл: Функция создаёт временный файл с помощью mktemp, в который записывается текущее содержимое командной строки.

  3. Открытие редактора: После создания временного файла, он открывается в указанном редакторе.

  4. Получение строки: После редактирования, содержимое временного файла считывается и подставляется обратно в READLINE_LINE.

  5. Удаление временного файла: Временный файл удаляется через команду rm.

Советы и дополнительные примечания

  • Проверьте, что у вас установлен редактор (например, nvim, vim, nano и т.д.) перед использованием этой функции. Это можно сделать, установив переменную EDITOR в вашем файле конфигурации Bash (~/.bashrc или ~/.bash_profile).
  • Убедитесь, что переменная READLINE_POINT устанавливается в конец строки для удобства редактирования.
  • Если вы используете нестандартные настройки Bash или хотите, чтобы ваша команда работала в различных версиях Bash, обязательно протестируйте функцию в средах, где вы собираетесь её использовать. Некоторые из assistive tools могут вести себя по-разному в зависимости от версии Bash.

Альтернативы в других оболочках

Если данное решение кажется сложным, стоит отметить, что в других оболочках, таких как Zsh, Fish и Nushell, подобная функция реализована по умолчанию. В таких оболочках редактирование команд в редакторе заканчивается их вставкой в командную строку, что может сильно упростить использование.

Заключение

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

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

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