Сочетание клавиш истории Bash для! *

8

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

  • !^ расширяется до первого аргумента предыдущей команды, например,

    $ echo one "two three"
    one two three
    $ echo !^
    echo one
    one
  • !$ расширяется до последнего аргумента предыдущей команды, например,

    $ echo one "two three"
    one two three
    $ echo !$
    echo "two three"
    two three
  • !* распространяется на все аргументы предыдущей команды, например,

    $ echo one "two three"
    one two three
    $ echo !*
    echo one "two three"
    one two three

(Насколько я понимаю, это синтаксически !!:^, !!:$и !!:*соответственно, где !!это обозначение событие , которое расширяется к предыдущей команде, и ^, $и *словесные обозначения, см Bash Reference Manual или man bash.)

Это часто довольно удобно. Но это становится еще круче с сочетаниями клавиш:

  • Когда вы нажимаете Alt+ .или Alt+ _, последний аргумент предыдущей команды вставляется в текущую команду, так же, как если бы вы написали !$в этот момент.

  • Также можно нажать Alt+ Ctrl+, yчтобы вставить первый аргумент предыдущей команды, как если бы вы написали !^в этот момент.

(См. Библиотеку GNU Readline или info readline.)

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

Есть ли такой ярлык? Если нет, то можно ли настроить библиотеку readline, чтобы добавить ее, и как?

Malte Skoruppa
источник
AFAIK, сочетания клавиш обрабатываются эмулятором терминала. Итак, я полагаю, вы используете gnome-терминал?
Сет
1
В zsh, если вы печатаете , echo !*а затем нажмите клавишу TAB, у вас есть желаемый эффект. В общем, TAB в режиме readline расширит все возможности расширения. Очень кстати; вероятно bash будет иметь какую-то конфигурацию для того же эффекта? @ Seth, я думаю, что это readline в bash, а не эмулятор терминала - не уверен, хотя.
Rmano
2
@ Нет, ярлыки из Q обрабатываются bash. Вы можете найти «Команды для манипулирования историей» в man bash(где-то в строке 3030)
Раду Рэдяну
@ RaduRădeanu Ох, интересно! Я этого не знал. Мой плохой за плохие предположения.
Сет
1
\e.и \e_сопоставлены с функцией readline yank-last-argи \e\C-yсопоставлены с yank-nth-arg. К сожалению, кажется, что нет (единственной) команды, которая добавляет несколько предыдущих аргументов одновременно.
Adaephon

Ответы:

5

Если вы посмотрите на вывод следующей команды:

bind -l

или лучше:

bind -l | grep arg

Вы можете видеть, что не существует никакой функции readline для всех аргументов, как, например, yank-last-argдля последнего аргумента - который может вставить последний аргумент в предыдущую команду (последнее слово предыдущей записи истории). Таким образом, если такой функции не существует, скорее всего, не существует ярлыка для выполнения того, что вы хотите.

Давайте попробуем составить один подход к вашему запросу ...

Сначала посмотрите, например, на вывод следующей команды:

bind -p | grep yank-nth-arg

Выход:

"\e\C-y": yank-nth-arg

и может быть переведен следующим образом: yank-nth-arg(который вставляет первый аргумент в предыдущую команду - с аргументом n, вставляет n-й аргумент из предыдущей команды) связан с Alt+ Ctrl+ y.

Таким же образом можно интерпретировать любую строку из вывода bind -pкоманды.

Теперь обратите внимание на следующие сценарии:

  • Если вы установили следующую привязку:

    bind '"\ea": "\e2\e."'

    Alt+ Aбудет сопоставлен с Alt+ 2Alt+, .который отображается для вставки второго аргумента предыдущей команды. Таким образом, после того, как вы нажмете Alt+ A, второй аргумент предыдущей команды будет вставлен в текущую команду.

  • Если вы установите:

    bind '"\ea": "\e1\e. \e2\e."'

    После того, как вы нажмете Alt+ A, первые два аргумента предыдущей команды будут вставлены в текущую команду. Если число аргументов предыдущей команды не превышает 2, то, конечно, вся предыдущая команда вставляется в текущую команду.

  • Если вы установите:

    bind '"\ea": "\e1\e. \e2\e. \e3\e."'

    После того, как вы нажмете Alt+ A, первые три аргумента предыдущей команды будут вставлены в текущую команду. Если количество аргументов предыдущей команды не более 3 (как в вашем случае), конечно, вся предыдущая команда вставляется в текущую команду.

  • И так далее.

Для первых 10 аргументов вы можете использовать:

bind '"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."'

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

Чтобы сделать его постоянным, добавьте следующую строку в ваш ~/.inputrcфайл:

"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."

В этом примере я выбрал Alt+, Aчтобы вставить все аргументы (если число аргументов не превышает 10) предыдущей команды, но вы можете выбрать любую другую комбинацию, которую вы используете, заменив в предыдущей команде \eaстроку.

Ресурсы:

Раду Рэдяну
источник
Ну, это несколько хакерски, и это будет работать только для ограниченного числа аргументов, но, похоже, это будет самое близкое, что мы можем легко получить - я возьму это;) На самом деле я только что взглянул на исходный код readline. На первый взгляд, похоже, что в файле funmap.cфункция yank-nth-argсопоставлена ​​с функцией C rl_yank_nth_arg, которая, в свою очередь, определена в kill.c. Аналогично для yank-last-arg. Конечно, было бы возможно расширить readline с такой функциональностью, но я не хочу этого делать; Я предпочитаю мой Readline будет управляться apt, и эта функция не что важно;)
Malte Skoruppa