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?

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!


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?
— Ricky,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.