Rozwiąż wszystkie aliasy w wierszu polecenia zsh

12

Zagnieżdżałem aliasy i chcę je wszystkie rozwiązać przed wykonaniem polecenia. W jaki sposób mogę to zrobić?

Jeśli jest funkcja, która nie jest powiązana z żadnym klawiszem, to też M-x foobarjest dla mnie w porządku. Mogę nawet użyć polecenia zewnętrznego ( type, command, which, cokolwiek). Próbowałem wszystkiego z wątku. Dlaczego nie użyć „który”? Czego więc użyć? ale nic nie działa.

WeSenseASoulInSearchOfAnswers
źródło
2
C-x arozwija alias pod kursorem (zakładając, że używasz systemu uzupełniania).
Stéphane Chazelas,
Prawo, _expand_alias (^Xa): expands the word the cursor is on if it is an alias. Jest to pomocne, jednak szkoda, że ​​w bash można rozwinąć całą linię, ale w zsh nie.
WeSenseASoulInSearchOfAnswers
Przypuszczam, że możliwe jest napisanie wiążącej się komendy, która wywołuje się, _expand_aliasdopóki bufor edycji nie zmieni się.
vinc17

Odpowiedzi:

10

Zauważ, że Ctrl-Alt-E in bashnie tylko rozwija aliasy. Rozszerza także zmienne, podstawianie poleceń (!), Podstawianie procesów (!), Interpretację arytmetyczną i usuwa cudzysłowy (nie generuje nazw plików (globbing) ani interpretacji tyldy).

Nie zawsze udaje się rozwinąć aliasy. Tak więc, chociaż ma swoje zastosowania, ważne jest, aby zdać sobie sprawę, że jego wynik potencjalnie zmienia znaczenie wiersza poleceń, ma skutki uboczne i jest potencjalnie niebezpieczny.

Na przykład w:

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

Jeśli nacisnę M-C-Etutaj, to daje mi:

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

Co daje mi zupełnie inną linię poleceń (i wyobraź sobie, co by się stało, gdybym miał rm -rf *zamiast pwdwyżej) i nie rozszerza fooaliasu.

Dzięki zsh, aby rozwinąć uwagę Gillesa na temat rozszerzonych funkcji aliasów, możesz:

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

Spowoduje to rozwinięcie aliasów tylko wtedy, gdy bieżący wiersz poleceń jest poprawny pod względem składniowym (dlatego też pełni funkcję sprawdzania składni).

W przeciwieństwie do bashMCE, rozwiązuje również w pełni aliasy. Na przykład, jeśli masz:

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

Zostanie rozszerzony do:

$ ls --color -l

Zauważ, że kanonizuje również składnię, więc rzeczy takie jak:

$ for i (*) cmd $i; foo

zostanie zmieniony na:

$ for i in *
        do
                cmd $i
        done
        foo
Stéphane Chazelas
źródło
To jest buggy. Jeśli mam alias ls='ls --color'i wpisz C-x apowyżej ls, otrzymuję: \ls --color(tak, że nowa lsnie jest mylnie interpretowane jako alias). Ale z twoim expand-aliasesrozumiem:, ls --colorczyniąc wynik niejednoznacznym.
vinc17
@ vinc17, nie jest dwuznaczny, ponieważ rozwiązuje alias w pełni (pod tym względem jest mniej błędny niż jego bashodpowiednik). Ale to prawda, że ​​po uruchomieniu polecenia otrzymasz kolejną rundę rozszerzenia aliasu (np. In bash), więc najlepiej byłoby tymczasowo wyłączyć rozszerzenie aliasu, więc na przykład zawiń to w (){ setopt localoptions noexpandalias; ...; }. Zauważ, że można powiedzieć, że _expand_aliasjest on błędny, a także rozszerza alias po uruchomieniu \ls.
Stéphane Chazelas
@ vinc17, że ucieczka odwrotnym ukośnikiem wykonana przez _expand_aliasjest również łatwo oszukać jak alias 'foo=repeat 3 foo'lub alias ls='ls --color'; alias '\ls=echo fooled'. Nie ma tutaj idealnego rozwiązania.
Stéphane Chazelas
Jeśli chodzi _expand_aliaso to alias 'foo=repeat 3 foo', uważam brakujący ukośnik za błąd. I alias '\ls=echo fooled'nie powinno być dozwolone; Wolę tu bash, który mówi: bash: alias: '\ls': invalid alias name.
vinc17
@ vinc17, nie widzę, jak można to postrzegać jako coś innego niż ograniczenie w bash. Jeśli nie lubisz aliasów z odwrotnymi ukośnikami, nie używaj ich, ale dlaczego chcesz, aby powłoka je odrzucała? Podczas gdy aliasy zastępują funkcje biednego człowieka w csh (skąd pochodzą), w powłokach podobnych do Bourne'a są hackami do robienia sztuczek, których nie można wykonać za pomocą funkcji, pewnego rodzaju makropolecenia, które przechwytuje na początku parsera powłoki , Nie widzę sensu w ograniczaniu tego, co może zrobić.
Stéphane Chazelas
6

Jeśli umieścisz wiersz polecenia w definicji funkcji, a następnie wydrukujesz funkcję, aliasy zostaną rozwinięte. Otrzymasz również znormalizowane białe znaki.

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

Aby umieścić to wszystko w interaktywnym poleceniu, możesz utworzyć widget ZLE. Możesz zdefiniować funkcję bezpośrednio, umieszczając jej kod we wpisie w functionstablicy; dostaniesz efekt normalizacji podczas czytania.

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

Otrzymujesz ten sam efekt normalizacji w preexechaku . Aliasy są również rozwijane w momencie automatycznego ładowania funkcji ( autoload -Ujest to powszechnie stosowane w celu uniknięcia rozszerzenia aliasu).

Funkcja _expand_aliasuzupełniania rozwija słowo pod kursorem, jeśli jest to alias. Używa aliasestablicy . To nie jest rekurencyjne. Możesz zaimplementować bardziej ogólny ekspander aliasów aliases, ale jest to nieco trudne, ponieważ ustalenie lokalizacji, w których aliasy są rozwijane, jest ściśle związane ze składnią powłoki.

Gilles „SO- przestań być zły”
źródło
2
Zawsze używałem autoload -Upo prostu dlatego, że zaleca to dokumentacja zsh, ale nigdy nie zrozumiałem, co -Uwłaściwie zrobiłem, dopóki tego nie przeczytałem :). Także dla wszystkich zainteresowanych, można powołać się na _expand_alias działać bezpośrednio, wpisując swój alias do linii poleceń, uderzając <Esc>, x, aby uruchomić minibufor następnie wpisując_expand_alias<Enter>
the_velour_fog
2

Jeśli masz wiele zagnieżdżonych fantazyjnych aliasów i nie masz pewności, co z nimi robi zsh oraz w jakiej kolejności są przekazywane polecenia, możesz zawsze uruchomić zsh z -xopcją. Spowoduje to wydrukowanie poleceń i argumentów podczas ich wykonywania.

Pamiętaj jednak, że ta opcja jest przeznaczona raczej do debugowania, więc drukuje wiele niepotrzebnych rzeczy zaraz po zsh -xwywołaniu (w zasadzie każda funkcja / widget / wtyczka twojego .zshrc), a podczas wykonywania polecenia może być również pełna, szczególnie jeśli zdefiniowałeś preexeci precmdzaczepisz.

Powinienem również wspomnieć, że drukuje tylko te polecenia, które są ostatecznie wykonywane, a oddzielne polecenia są drukowane osobno, więc po

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

Zobaczysz

+zsh:1> echo a
a
+zsh:1> echo b
b
+zsh:1> echo d
d
jimmij
źródło