Habillage d'une commande qui comprend des guillemets simples et doubles pour une autre commande

10

J'ai récemment découvert la montre , mais j'ai du mal à la faire fonctionner avec des commandes relativement sophistiquées.

Par exemple, je voudrais demander watchd'exécuter la commande suivante zshtoutes les trois secondes * :

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

comme vous pouvez le voir, la ligne ci-dessus comprend des guillemets simples, des guillemets doubles, entre autres caractères spéciaux.

J'ai donc essayé:

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

mais j'ai eu:

aucune correspondance trouvée pour x in! @ # $ # ....; terminé

J'ai essayé d'autres combinaisons sans succès. Voici l'une de ces tentatives:

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

ce qui entraîne également une erreur similaire.

Des idées sur la façon de faire fonctionner cela?


* Je serais également intéressé par des solutions qui fonctionnent surbash

Amelio Vazquez-Reina
la source

Réponses:

16

Conseil général: si vous avez deux niveaux d'imbrication, évitez d'utiliser des guillemets simples dans la commande interne et utilisez des guillemets simples autour de la commande externe.

Astuce supplémentaire: n'utilisez pas de backticks - `…` - pour exécuter du code, utilisez-le à la place $(…). Dollar-parentheses est à peu près DWIM ('Faites ce que je veux dire') quand il s'agit de citations imbriquées; les backquotes ont des règles arcanes, dépendantes du shell.

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

Si vous avez besoin de guillemets simples dans une commande entre guillemets simples, vous pouvez utiliser '\''. Considérez ces quatre caractères comme le moyen de citer un guillemet simple à l'intérieur de guillemets simples, bien que techniquement parlant cela soit construit comme fin de la chaîne entre guillemets simples, ajoutez un guillemet simple littéral et commencez une nouvelle chaîne entre guillemets simples (toujours annexée à la mot actuel).

Pour les cas plus complexes, comptez minutieusement les guillemets ou définissez des variables temporaires.

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

Cette réponse n'est pas spécifique à zsh. Zsh n'apporte rien de majeur ici. Vous pouvez économiser un peu de guillemets car il n'y a pas besoin de guillemets doubles autour des substitutions de commandes, et parfois il existe des moyens d'utiliser des commandes intégrées plutôt que des commandes externes qui réduisent les besoins de guillemets, mais les problèmes sous-jacents sont les mêmes que dans d'autres shells.

Oh, et en passant, notez que watchcela exécutera votre commande dans sh, pas dans zsh. Si vous souhaitez exécuter la commande dans zsh, vous devez exécuter

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

sur Debian / Ubuntu, et

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

(encore plus de citations!) ailleurs.

Gilles 'SO- arrête d'être méchant'
la source
Merci @Gilles. C'était très utile. Fait intéressant, watchne vient pas avec les options -xni -csur ma machine. Je l'ai consulté en ligne et je n'ai trouvé aucune page de manuel qui les mentionne. Que font ces options?
Amelio Vazquez-Reina
1
@intrpc -xindique de watchne pas passer la commande via un shell. Je viens de découvrir que c'est spécifique à Debian / Ubuntu, même si ce n'est pas indiqué comme tel. Le -cest transmis à zsh, pas à watch.
Gilles 'SO- arrête d'être méchant'
Les @Gilles -xet les -execoptions à la fois existez dans mon watch(sur gentoo), donc ce n'est certainement pas spécifique à Debian. Peut-être que vous avez comparé avec une autre version de watch? Le mien vient du package procps .
rozcietrzewiacz
1
@rozcietrzewiacz watchvient aussi de procpsDebian. La source officielle n'a pas --exec. Le paquet dans Debian (et ses dérivés, y compris Ubuntu) ajoute l'option dans un correctif spécifique à Debian ( watch_exec_beep.patch; il s'agit du «correctif d'exécution de Mortys watch» du bogue # 410967 ). Gentoo a peut-être adopté un patch similaire.
Gilles 'SO- arrête d'être méchant'