2015-02-18 16 views
7

Próbuję uruchomić polecenie ze zmiennej w skrypcie powłoki. Użyta powłoka to powłoka bash.Uruchom polecenie powłoki ze zmiennej w skrypcie powłoki

Plik exp zawiera:

abcdef 

wykonując następujące polecenie:

sed s/b/\/exp 

... produkuje wyjście:

a cdef 

Ale wykonującym:

cmd="sed s/b/\/exp" 
echo $cmd 
$cmd 

... produkuje następujący błąd:

sed s/b/\/exp 
sed: -e expression #1, char 5: unterminated `s' command 

widzę, że dodanie eval przed wykonaniem robót. Ale nie mogę zrozumieć, dlaczego. Czy potrafisz wyjaśnić, dlaczego jedna metoda działa, a druga nie działa?

+9

Nie umieszczaj poleceń w łańcuchach. Jak widzieliście, nie zawsze działa. Oto kilka [zalecane czytanie] (http://mywiki.wooledge.org/BashFAQ/050). –

+1

Dzięki za odpowiedź i link – Yosha

+2

możliwy duplikat [jak umieścić wszystkie argumenty polecenia w jednej zmiennej] (http://stackoverflow.com/questions/28542911/how-to-put-all-command-arguments-in- jedna zmienna) – tripleee

Odpowiedz

0

ten powinien zrobić:

cmd=$(sed "s/b/\ /" exp) 

do przechowywania danych w zmiennej użytku var=$(commands)

+2

Jeśli piszesz odpowiedź na to pytanie, to znaczy, że nikt inny nie powinien pisać ah? –

+0

@ Karthikeyan.R.S Oczywiście każdy może opublikować, co chcą, ale wysyłanie w 100% takie same jak inne nie są potrzebne. – Jotne

+1

Ta odpowiedź nie dotyczy pierwotnego pytania, które dotyczyło przechowywania samego polecenia (nie jego danych wyjściowych) w zmiennej, a następnie robienia czegoś ze zmienną, aby uruchomić polecenie. –

1

Jeśli potrzebujesz wyjście w zmiennej a następnie użyć,

cmd=$(sed 's/b/ /' exp) 

Jak @thomas mówi: Jeśli używasz zmiennej, możesz użyć podwójnych cudzysłowów.

+1

To jest to samo co opublikowałem. – Jotne

+1

Czy możesz powiedzieć "Powód przegłosowania"? –

+1

To samo co mój wpis, – Jotne

0

Jeśli cytujesz SED parametrów, skrypt jest łatwiejszy do odczytania, a backslashe są potrzebne tylko do ucieczki znaków specjalnych (takich jak backslashem i podwójnie cudzysłowów): Jeśli korzystasz z jedno-

cmd=$(sed "s/b/ /" exp) 

cytaty, które zmniejsza zapotrzebowanie na ucieczkę więcej - ale uniemożliwia korzystanie zmiennych takich jak to:

xxx=something 
cmd=$(sed "s/b/$xxx/" exp) 
+1

To jest to samo, co opublikowany – Jotne

+4

, który edytowaliśmy w tym samym czasie - więc wskazałem kilka dodatkowych funkcji, których nie dodałeś (jeszcze) do swojej odpowiedzi. –

+3

@Jotne, że napisałeś podobne pytanie w ciągu kilku sekund. A ten przynajmniej ma jakieś wyjaśnienie. Nie wydaje mi się, żeby to uczciwe, aby je zarzucić. – fedorqui

3

wygląda jak cytuje wydania:

cmd="sed s/b/\/exp" powoduje, że $cmd trzyma sekwencję znaków bez specjalnego znaczenia. Twój \ nie ucieknie z twojej przestrzeni.

eval traktuje tę sekwencję znaków jako polecenie i ponownie przypisuje specjalne znaczenie do Twojego \.

Zobacz także: Preserving quotes in bash function parameters

6

Problem masz to, że sama przestrzeń nie jest prawidłowo interpretowany przez bash.

Zobacz jak to działa dobrze, jeśli zastąpi b z innym charakterze, powiedzmy X:

$ cmd="sed s/b/X/ exp" 
$ $cmd 
aXcdef 

więc obejście jest użycie szesnastkowy dla przestrzeni, która jest 20:

$ cmd="sed s/b/\x20/ exp" 
$ $cmd 
a cdef 

Lub użyć eval do wykonania samego polecenia:

$ cmd="sed s/b/\/exp" 
$ eval "$cmd" 
a cdef 

Jak zasugerował Tom Fenech, przechowywanie poleceń w zmiennych nie jest dobrym podejściem, jak opisano w I'm trying to put a command in a variable, but the complex cases always fail!. Może czasem działać, ale w innych przypadkach może dawać nieprzewidywalne rezultaty. Alternatywą jest rozważenie użycia funkcji.

Wreszcie, uwaga eval może się przydać w takich przypadkach, tylko że jest bardzo ostrożny w przechowywaniu. Trochę dobrego czytania: Variable as command; eval vs bash -c.

+1

Cóż ... powiedział "bash", ale z reguły nie zacznę od wprowadzenia początkującego rozszerzenia bash (\ x20), nie zauważając, że nie jest to POSIX.Zamiast tego, typ ucieczki i powody dla nich byłyby zwykłym miejscem do rozpoczęcia. –

Powiązane problemy