Komenda Bash w ciągu znaków jest wykonywana podczas tworzenia ciągu, a nie kiedy go później używam
10
Jestem stosunkowo nowym użytkownikiem skryptów powłoki, ale prawie ukończyłem skrypt, który korzysta z programu lftp . Część skryptu, z którą mam problem, polega na tym, że tworzę długi ciąg poleceń (oddzielonych przez ;).
for var in something
do...
commands_to_run+="echo Result is `tail -n 1 $somefile`;"done
Zauważam, że tailprogram - owinięty w backtyki - jest uruchamiany, gdy iteruje pętla for, ale nie, gdy wywołuję ciąg poleceń później w moim skrypcie.
Niestety zawartość $ somefile nie jest na tym etapie gotowa do sprawdzenia. Jak mogę uzyskać polecenie do wykonania, gdy go potrzebuję, a nie podczas tworzenia ciągu?
Ten jest nieco trudny. Informacje dostarczone przez Hauke są poprawne, wystarczy przeanalizować je pod kątem swojego przypadku użycia.
Najprostszym sposobem jest użycie $()składni podczas ucieczki przed $taką, że definicja zmiennej nie wykonuje polecenia zawartego $()w momencie definicji. Zastrzeżenie polega na tym, że wynik końcowy musi być następnie ponownie oceniony (przez eval) przez powłokę w czasie faktycznego wykonania, aby zagnieżdżone polecenie mogło zostać wykonane.
Przykład jest o wiele łatwiejszy, więc weź ten, który powinien postawić cię na właściwej drodze:
for((i=0;i<10;i++));do
date +%s.%N # Print a timestamp (in format seconds.nanoseconds)
test="echo \$(date +%s.%N)"# Save a command to do the same
sleep 1# Sleep for a secondeval"$test"# Evaluate the command saved in variable 'test'
echo # Print a new line before the next iterationdone
Oto przykładowe dane wyjściowe z powyższego przykładu (przycięte do jednej iteracji):
1398832186.1336613441398832187.139076728
Zauważysz, że drugi znacznik czasu dla każdej pętli jest mniej więcej sekundę po pierwszej. I odwrotnie, jeśli wykonasz ten sam test bez uciekania się $do testdefinicji i usunięcia eval, dwa znaczniki czasu będą prawie pasować.
Nie przyzwyczajaj się do używania evalw większości sytuacji, ale jest to jedna z tych, w których nie znam dobrego sposobu na uniknięcie tego. Mam nadzieję, że to pomaga. Powodzenia!
Bardzo dziękuję, próbowałem użyć $(...)zgodnie z sugestią Hauke, ale odwrotny ukośnik jest kluczem.
Ricky,
Cieszę się, że pomogło - pamiętajcie jednak, że kluczem jest tutaj naprawdę to, evalże można zrobić to samo, nie uciekając przed $i używając pojedynczych cudzysłowów ( ') zamiast podwójnych cudzysłowów ( "), aby otoczyć polecenie.
daBeamer
Teraz właśnie zdałem sobie sprawę, podobnie jak sugestie Huake'a, kiedy spróbuję użyć tego w programie lftp, echo po prostu wypisuje polecenie, tak naprawdę go nie uruchomi. Być może trzeba będzie wypróbować ich listę mailingową, aby uzyskać bardziej szczegółową pomoc.
Ricky,
Jakie polecenie próbujesz wykonać? Miałem wrażenie, że chcesz napisać echociąg z zawartością, w tym wynik zagnieżdżonego polecenia opóźnionego wykonania.
daBeamer
1
@Ricky Musiałbym się zgodzić ze wszystkimi punktami z @HaukeLaging. Kod „tak jak jest minus” echonie zadziała, ponieważ nie ma komendy eval, tylko ciąg znaków. Jeśli masz dla nas bardziej odpowiedni przykład, możemy spróbować pomóc.
daBeamer
6
Istnieje kilka poziomów cytowania. Cudzysłowy ( "...") ochrony odstępy i kilka znaków specjalnych ( ~, &, |, ;, ...), ale nie uniemożliwia rozszerzenie parametrów i podstawienia polecenia.
Potrzebujesz „pojedynczego cudzysłowu” ( ') lub ukośnika przed „niebezpiecznymi” znakami.
Ogólnie: należy rozważyć użycie $(tail ...)zamiast backticks. Backticks są starszym standardem, ale mówimy o tak starym, że $()nie powoduje problemów dla większości ludzi. Nowa wersja jest łatwiejsza do odczytania i można ją zagnieżdżać. Nie mówiąc już o problemach z formatowaniem tutaj na sx ...
Dzięki za szybką odpowiedź Hauke. Niestety zastąpienie backticks zalecanym $(...)nadal daje ten sam wynik - powłoka wykonuje to, gdy mój ciąg jest zdefiniowany.
Ricky,
@Ricky To nie były alternatywne sugestie. Powinieneś użyć, $()ale i tak potrzebujesz pojedynczych cudzysłowów.
Hauke Laging
Więc żadna kombinacja tych postaci nie osiągnie tego, o co mi chodzi?
Ricky,
@ Ricky Co tak trudno zrozumieć na temat „Potrzebujesz jednego cudzysłowu”? Oczywiście nawet nie próbujesz.
Hauke Laging
Właściwie to zrobiłem, ale kiedy użyję pojedynczych cudzysłowów, echo wypisze wszystko w tym wierszu jako normalny ciąg. Co jest takiego trudnego w zapewnieniu przykładu?
$(...)
zgodnie z sugestią Hauke, ale odwrotny ukośnik jest kluczem.eval
że można zrobić to samo, nie uciekając przed$
i używając pojedynczych cudzysłowów ('
) zamiast podwójnych cudzysłowów ("
), aby otoczyć polecenie.echo
ciąg z zawartością, w tym wynik zagnieżdżonego polecenia opóźnionego wykonania.echo
nie zadziała, ponieważ nie ma komendyeval
, tylko ciąg znaków. Jeśli masz dla nas bardziej odpowiedni przykład, możemy spróbować pomóc.Istnieje kilka poziomów cytowania. Cudzysłowy (
"..."
) ochrony odstępy i kilka znaków specjalnych (~
,&
,|
,;
, ...), ale nie uniemożliwia rozszerzenie parametrów i podstawienia polecenia.Potrzebujesz „pojedynczego cudzysłowu” (
'
) lub ukośnika przed „niebezpiecznymi” znakami.Ogólnie: należy rozważyć użycie
$(tail ...)
zamiast backticks. Backticks są starszym standardem, ale mówimy o tak starym, że$()
nie powoduje problemów dla większości ludzi. Nowa wersja jest łatwiejsza do odczytania i można ją zagnieżdżać. Nie mówiąc już o problemach z formatowaniem tutaj na sx ...źródło
$(...)
nadal daje ten sam wynik - powłoka wykonuje to, gdy mój ciąg jest zdefiniowany.$()
ale i tak potrzebujesz pojedynczych cudzysłowów.