2010-07-05 19 views
5

Jak napisać funkcję w bash, który wykonuje polecenia, że ​​jest on podany jako argument, gdzieBash funkcja polecenia nazywając podane jako argument

  • Podana komenda może być aliasem
  • Argumenty muszą być przekazane dokładnie tak, jak dane; bez dokonania oceny mogą być wykonane

Innymi słowy, jak napisać jako przezroczysty-as-możliwe otoki funkcję.

Celem funkcji owijania może być na przykład ustawienie katalogu bieżącego przed i po podanej komendzie i/lub ustawienie zmiennych środowiskowych, lub czas trwania danego polecenia, ... Jako prosty przykład tutaj Biorę funkcję, która po prostu drukuje linię, a następnie wykonuje podane polecenie.

Pierwsza próba:

function wrap1 { 
    echo Starting: "[email protected]" 
    "[email protected]" 
} 

Można go używać jak wrap1 echo hello. Ale problem polega na tym, że nie można wykonać alias myalias echo, a następnie wywołać wrap1 myalias hello: nie rozwiąże to aliasu.

Kolejna próba z użyciem eval:

function wrap2 { 
    echo Starting: "[email protected]" 
    eval "[email protected]" 
} 

Teraz wywołanie prace aliasu. Ale problem polega również na ocenie argumentów. Na przykład wrap2 echo "\\a" drukuje po prostu a zamiast \a, ponieważ argumenty są oceniane dwukrotnie.

shopt -s expand_aliases również nie pomaga.

Czy istnieje sposób na obu aliasów takich jak wrap2, ale nadal przekazywać argumenty bezpośrednio jak wrap1?

+1

Twoja pierwsza funkcja jest drogą do zrobienia. Poddaj się poprawnie obsłudze aliasów. ["W niemal każdym celu preferowane są funkcje powłoki zamiast aliasów."] (Http://www.gnu.org/software/bash/manual/html_node/Aliases.html#Aliases) –

+0

[Wymagane czytanie] (http://mywiki.wooledge.org/BashFAQ/050) –

Odpowiedz

7

Ty (uh, ja) możesz użyć printf% q, aby uciec od argumentów. Na pierwszy rzut oka, ucieczka z printf, a następnie wykonanie eval zawsze daje taki sam wynik, jak bezpośrednie przekazywanie argumentów.

wrap() { 
    echo Starting: "[email protected]" 
    eval $(printf "%q " "[email protected]") 
} 
+0

Co to jest 'command = $ (shift)'? AFAIK 'shift' nie pisze na standardowe wyjście. – Philipp

+0

Ale 'printf"% q "' wygląda bardzo obiecująco. Czy to też działa dla pośrednich lub rekurencyjnych aliasów? – Philipp

+0

Awtch, the $ (shift) było oczywiście nie tak. Naprawione. W rzeczywistości nie ma nawet powodu, aby odróżniać pierwsze "słowo" (ewentualnie alias) od reszty polecenia w ogóle. –

0

To wydaje się być możliwe z podwójnym eval:

eval "eval x=($(alias y | cut -s -d '=' -f 2))" 
# now the array x contains the split expansion of alias y 
"${x[@]}" "${other_args[@]}" 

Więc może czynność można zapisać następująco:

wrap() { 
    eval "eval prefix=($(alias $1 | cut -s -d '=' -f 2))" 
    shift 
    "${prefix[@]}" "[email protected]" 
} 

Jednak eval jest zła, a następnie dwukrotnie eval jest podwójnie zła , a aliasy nie są rozwijane w skryptach z jakiegoś powodu.

+0

Zgadzam się, że zwykle rozwijanie aliasów w skrypcie nie jest dobrym pomysłem, ponieważ nie chcesz, aby alias użytkownika zmienił to, co robi polecenie w skrypcie. Ale to nie ma znaczenia, ponieważ polecenie, w którym próbuję rozwinąć alias, nie jest poleceniem skryptu, jest to polecenie wpisane przez użytkownika. –

+0

Zakładam, że chodziło o "alias $ 1" zamiast "alias y" w wrap(). To, co się robi, to w zasadzie ponowne implementowanie alias-resolving. Mam nadzieję, że można tego uniknąć, ale jeśli tak naprawdę nie ma innego sposobu, to takie podejście może rzeczywiście zadziałać, dziękuję. Aby ukończyć rozwiązanie, trzeba by było również zająć się komendami, które nie są aliasami, aliasami rozwiązującymi inne aliasy, aliasy rekurencyjne, ... Obawiam się, że rozwinie się to na pewną bestię. –

+0

Dzięki, poprawiono "y" → '$ 1'. – Philipp