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?

Ricky
źródło

Odpowiedzi:

8

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 second
  eval "$test" # Evaluate the command saved in variable 'test'
  echo         # Print a new line before the next iteration
done

Oto przykładowe dane wyjściowe z powyższego przykładu (przycięte do jednej iteracji):

1398832186.133661344
1398832187.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!

daBeamer
źródło
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 ...

Hauke ​​Laging
źródło
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?
Ricky,