Zawijanie polecenia zawierającego pojedyncze i podwójne cudzysłowy dla innego polecenia

10

Niedawno dowiedziałem się o zegarku , ale mam problem z uruchomieniem go przy użyciu stosunkowo wyrafinowanych poleceń.

Na przykład chciałbym prosić watcho uruchomienie następującego polecenia zshco trzy sekundy * :

for x in `command_1 | grep keyword | cut -d' ' -f1`; do command_2 "word[word=number]" $x; done

jak widać powyższa linia zawiera pojedyncze cudzysłowy, podwójne cudzysłowy i inne znaki specjalne.

Więc próbowałem:

watch -n 3 "for x in `my_command | grep keyword | cut -d' ' -f1`; do command2 "rusage[mem=7000]" $x; done"

ale potem dostałem:

nie znaleziono dopasowań dla x in! @ # $ # ....; gotowy

Próbowałem innych kombinacji bez powodzenia. Oto jedna z tych prób:

watch -n 3 "for x in $(bjobs -w | grep pre_seg | cut -d' ' -f1); do bmod -R "rusage[mem=7000]" $x; done"

co powoduje również podobny błąd.

Jakieś pomysły, jak to zrobić?


* Byłbym zainteresowany także rozwiązaniami, które działająbash

Amelio Vazquez-Reina
źródło

Odpowiedzi:

16

Wskazówka ogólna: jeśli masz dwa poziomy zagnieżdżania, unikaj używania pojedynczych cudzysłowów w poleceniu wewnętrznym i używaj pojedynczych cudzysłowów wokół polecenia zewnętrznego.

Dodatkowa wskazówka: nie używaj odwrotnych znaków - `…` - do wykonania kodu, zamiast tego używaj $(…)go wokół niego. Nawiasy w dolarach są w zasadzie DWIM („Zrób to, co mam na myśli”), jeśli chodzi o zagnieżdżone cudzysłowy; cudzysłowy mają tajemne, zależne od powłoki reguły.

watch -n 3 'for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'

Jeśli potrzebujesz pojedynczych cudzysłowów w poleceniu pojedynczego cudzysłowu, możesz użyć '\''. Pomyśl o tych czterech znakach jako sposobie cytowania pojedynczego cytatu w pojedynczych cudzysłowach, chociaż technicznie rzecz biorąc, jest on skonstruowany jako zakończenie łańcucha pojedynczego cudzysłowu, dołącz dosłowny pojedynczy cudzysłów i rozpocznij nowy ciąg pojedynczego cudzysłowu (nadal dołączany do aktualne słowo).

W przypadku bardziej skomplikowanych przypadków należy skrupulatnie policzyć cudzysłowy lub zdefiniować zmienne tymczasowe.

cmd='for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'
watch_cmd='watch -n 3 "$cmd"'

Ta odpowiedź nie jest specyficzna dla zsh. Zsh nie przynosi tu nic ważnego. Możesz zaoszczędzić trochę na cytowaniu, ponieważ nie ma potrzeby podwójnego cudzysłowu wokół podstawiania poleceń, a czasami istnieją sposoby użycia wbudowanych zamiast zewnętrznych poleceń, które zmniejszają potrzeby cytowania, ale podstawowe problemy są takie same jak w innych powłokach.

Aha, nawiasem mówiąc, zauważ, że watchwykona twoje polecenie w sh, a nie w Zsh. Jeśli chcesz wykonać polecenie w zsh, musisz uruchomić

watch -n 3 -x zsh -c "$cmd"

na Debian / Ubuntu i

export cmd
watch -n 3 'exec zsh -c "$cmd"'

(jeszcze więcej cytatów!) w innym miejscu.

Gilles „SO- przestań być zły”
źródło
Dzięki @Gilles. To było bardzo pomocne. Co ciekawe, watchnie ma opcji -xnor -cna moim komputerze. Sprawdziłem to online i nie znalazłem żadnych stron podręcznika, które by je wspominały. Co robią te opcje?
Amelio Vazquez-Reina
1
@intrpc -xmówi, watchaby nie przekazywać polecenia przez powłokę. Właśnie dowiedziałem się, że jest to specyficzne dla Debian / Ubuntu, nawet jeśli nie jest to oznaczone jako takie. -cJest przekazywany zsh, nie watch.
Gilles 'SO - przestań być zły'
@Gilles Obie opcje -xi -execistnieją w moim watch(na Gentoo), więc zdecydowanie nie jest to specyficzne dla Debiana. Może porównałeś się z inną wersją watch? Mój pochodzi z pakietu procps .
rozcietrzewiacz
1
@rozcietrzewiacz również watchpochodzi z procpsDebiana. Oficjalne źródło nie ma --exec. Pakiet w Debianie (i jego pochodnych, w tym Ubuntu) dodaje opcję w watch_exec_beep.patchłatce specyficznej dla Debiana ( ; jest to „łatka wykonawcza Mortysa oglądająca” z błędu # 410967 ). Gentoo mogło przyjąć podobną łatkę.
Gilles 'SO - przestań być zły'