Разрешить все псевдонимы в командной строке zsh

12

У меня есть вложенные псевдонимы, и я хочу разрешить все из них перед выполнением команды. Как мне это сделать?

Если есть функция, которая не привязана ни к каким клавишам, то M-x foobarэто тоже хорошо для меня. Я мог бы даже использовать внешнюю команду ( type, command, which, что угодно). Я попробовал все из потока Почему бы не использовать "который"? Что использовать тогда? но ничего не работает.

WeSenseASoulInSearchOfAnswers
источник
2
C-x aрасширяет псевдоним под курсором (при условии, что вы используете систему завершения).
Стефан Шазелас
Правильно _expand_alias (^Xa): expands the word the cursor is on if it is an alias. Это полезно, но, тем не менее, очень жаль, что в bash можно расширить всю строку, а в zsh - нет.
WeSenseASoulInSearchOfAnswers
Я предполагаю, что можно написать привязываемую команду, которая будет вызываться _expand_aliasдо тех пор, пока буфер редактирования больше не изменится.
vinc17

Ответы:

10

Обратите внимание, что Ctrl-Alt-E in bashне только расширяет псевдонимы. Он также расширяет переменные, подстановку команд (!), Подстановку процессов (!), Арифметическое расширение и удаляет кавычки (он не выполняет генерацию имени файла (глобализация) или расширение тильды).

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

Например, в:

$ a=';w' b=1
$ alias foo=bar
$ b=2; echo $b $a; cd /tmp/dir && for i do foo $(pwd) <(ls); done

Если я нажму M-C-Eздесь, это даст мне:

$ b=2; echo 1 ;w; cd /tmp/dir && for i do foo / /dev/fd/63; done

Что дает мне совершенно другую командную строку в целом (и представьте, что случилось бы, если бы я имел rm -rf *вместо pwdвышеупомянутого) и не расширяет fooпсевдоним.

С учетом записи zshЖиля о псевдонимах, расширенных внутри функций, вы можете сделать:

expand-aliases() {
  unset 'functions[_expand-aliases]'
  functions[_expand-aliases]=$BUFFER
  (($+functions[_expand-aliases])) &&
    BUFFER=${functions[_expand-aliases]#$'\t'} &&
    CURSOR=$#BUFFER
}

zle -N expand-aliases
bindkey '\e^E' expand-aliases

Это расширит псевдонимы только в том случае, если текущая командная строка синтаксически допустима (поэтому она выполняет функцию проверки синтаксиса).

В отличие от bashMCE, он также полностью разрешает псевдонимы. Например, если у вас есть:

$ alias ll='ls -l'; alias ls='ls --color'
$ ll

Будет расширен до:

$ ls --color -l

Обратите внимание, что он также канонизирует синтаксис, например:

$ for i (*) cmd $i; foo

будет изменено на:

$ for i in *
        do
                cmd $i
        done
        foo
Стефан Шазелас
источник
Это глючит. Если у меня есть alias ls='ls --color'и введите C-x aболее ls, я получаю: \ls --color(чтобы новое lsне было неправильно истолковано как псевдоним). Но с твоей expand-aliasesя получаю ls --color, делая результат неоднозначным.
vinc17
@ vinc17, это не является двусмысленным в том смысле, что он полностью разрешает псевдоним (в этом отношении он менее глючит, чем bashэквивалент). Но это правда, что если вы запустите команду после этого, вы получите еще один раунд раскрытия псевдонимов (например, в bash), поэтому в идеале вам нужно временно отключить раскрытие псевдонимов, например, обернуть его в a (){ setopt localoptions noexpandalias; ...; }. Обратите внимание, что вы можете сказать, что _expand_aliasон глючит, так как он расширяет псевдоним при запуске \ls.
Стефан Шазелас
@ vinc17, что экранирование от обратной косой черты _expand_aliasтакже легко обмануть, как alias 'foo=repeat 3 foo'или alias ls='ls --color'; alias '\ls=echo fooled'. Здесь нет идеального решения.
Стефан Шазелас
Что _expand_aliasкасается alias 'foo=repeat 3 foo', я бы расценил отсутствующий обратный слеш как ошибку. И alias '\ls=echo fooled'не должно быть позволено; здесь я предпочитаю Баш, который говорит: bash: alias: '\ls': invalid alias name.
vinc17
@ vinc17, я не вижу, как это можно рассматривать как что-то еще, кроме ограничения bash. Если вам не нравятся псевдонимы с обратной косой чертой, не используйте их, но почему вы хотите, чтобы оболочка отклоняла их? В то время как псевдонимы являются заменой функций бедного человека в csh (откуда они берутся), в оболочках, подобных Bourne, они являются хакерами для выполнения трюков, которые не могут быть выполнены с помощью функций, некоторой формы раскрытия макросов, которая перехватывается на ранних этапах синтаксического анализатора оболочки. Я не вижу смысла ограничивать то, что он может сделать.
Стефан Шазелас
6

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

% alias foo='bar -1'
% alias bar='qux -2'
% f () foo -3
% which f
f () {
        qux -2 -1 -3
}

Чтобы поместить все это в интерактивную команду, вы можете создать zle-виджет. Вы можете определить функцию напрямую, вставив ее код в запись в functionsмассиве; Вы получите эффект нормализации, когда будете читать обратно.

normalize-command-line () {
  functions[__normalize_command_line_tmp]=$BUFFER
  BUFFER=${${functions[__normalize_command_line_tmp]#$'\t'}//$'\n\t'/$'\n'}
  ((CURSOR == 0 || CURSOR = #BUFFER)
  unset 'functions[__normalize_command_line_tmp]'
}
zle -N normalize-command-line
bindkey  normalize-command-line

Вы получаете тот же эффект нормализации в preexecкрючке . Псевдонимы также раскрываются во время автозагрузки функции ( autoload -Uобычно используется, чтобы избежать расширения псевдонимов).

Функция _expand_aliasзавершения расширяет слово под курсором, если это псевдоним. Он использует aliasesмассив . Это не рекурсивно. Вы можете реализовать более общий расширитель псевдонимов, используя его aliases, но это несколько сложно, потому что выяснение местоположений, в которых раскрываются псевдонимы, тесно связано с синтаксисом оболочки.

Жиль "ТАК - перестань быть злым"
источник
2
Я всегда использовал autoload -Uпросто, потому что документация zsh рекомендует это, но я никогда не понимал, что на -Uсамом деле делал, пока не прочитал это :). Кроме того, для тех , кто заинтересован, можно ссылаться на _expand_alias работать непосредственно введя свой псевдоним в командной строке, поражая <Esc>, xдля запуска минибуфер, затем набрав_expand_alias<Enter>
the_velour_fog
2

Если у вас много вложенных необычных псевдонимов, и вы не уверены, что на самом деле делает с ними zsh и в каком порядке они передаются в команду, вы всегда можете запустить zsh с -xпараметром. Это выведет команды и аргументы по мере их выполнения.

Однако имейте в виду, что эта опция предназначена скорее для целей отладки, поэтому она печатает много бесполезных вещей сразу после zsh -xвызова (в основном, каждая функция / виджет / плагин вашего .zshrc), и во время выполнения команды она также может быть многословной, особенно если вы определили preexecи precmdподключите.

Следует также отметить, что он печатает только те команды, которые в конечном итоге выполняются, а отдельные команды печатаются отдельно, поэтому после

alias a='echo a'
alias b='echo b'
alias c='echo c'
alias d='echo d'
a && b || c; d

Ты увидишь

+zsh:1> echo a
a
+zsh:1> echo b
b
+zsh:1> echo d
d
jimmij
источник