Ajustar un comando que incluye comillas simples y dobles para otro comando

10

Recientemente aprendí sobre watch , pero tengo problemas para que funcione con comandos relativamente sofisticados.

Por ejemplo, me gustaría solicitar watchejecutar el siguiente comando zshcada tres segundos * :

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

Como puede ver, la línea anterior incluye comillas simples, comillas dobles, entre otros caracteres especiales.

Entonces intenté:

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

pero luego obtuve:

no se encontraron coincidencias para x in! @ # $ # ....; hecho

Probé otras combinaciones sin éxito. Aquí hay uno de esos intentos:

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

que también da como resultado un error similar.

¿Alguna idea de cómo hacer que esto funcione?


* También me interesarían las soluciones que funcionan enbash

Amelio Vazquez-Reina
fuente

Respuestas:

16

Consejo general: si tiene dos niveles de anidamiento, evite usar comillas simples en el comando interno y use comillas simples alrededor del comando externo.

Consejo adicional: no use backticks `…` - para ejecutar código, en su lugar use $(…)alrededor. El paréntesis en dólares es casi DWIM ('Haz lo que quiero decir') cuando se trata de comillas anidadas; las comillas inversas tienen reglas arcanas dependientes de shell.

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

Si necesita comillas simples dentro de un comando entre comillas simples, puede usar '\''. Piense en estos cuatro caracteres como la forma de citar una comilla simple dentro de comillas simples, aunque técnicamente hablando esto se construye como el final de la cadena entre comillas simples, agregue una comilla simple literal y comience una nueva cadena entre comillas simples (todavía adjunta al palabra actual).

Para casos más complejos, cuente minuciosamente las citas o defina variables temporales.

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

Esta respuesta no es específica de zsh. Zsh no trae nada importante aquí. Puede guardar un poco de comillas porque no hay necesidad de comillas dobles alrededor de las sustituciones de comandos, y a veces hay formas de usar funciones incorporadas en lugar de comandos externos que reducen las necesidades de comillas, pero los problemas subyacentes son los mismos que en otros shells.

Ah, y por cierto, tenga en cuenta que watchejecutará su comando en sh, no en zsh. Si desea ejecutar el comando en zsh, debe ejecutar

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

en Debian / Ubuntu, y

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

(¡incluso más citas!) en otra parte.

Gilles 'SO- deja de ser malvado'
fuente
Gracias @Gilles. Eso fue muy útil. Curiosamente watchno viene con las opciones -xni -cen mi máquina. Lo busqué en línea y no he encontrado ninguna página de manual que los mencione. ¿Qué hacen estas opciones?
Amelio Vazquez-Reina
1
@intrpc -xle dice que watchno pase el comando a través de un shell. Me acabo de enterar de que esto es específico de Debian / Ubuntu, a pesar de que no está indicado como tal. El -cse pasa a zsh, no a watch.
Gilles 'SO- deja de ser malvado'
@Gilles Las opciones -xy -execexisten en my watch(en gentoo), por lo que definitivamente no es específico de Debian. Tal vez lo comparaste con alguna otra versión de watch? El mío proviene del paquete procps .
rozcietrzewiacz
1
@rozcietrzewiacz también watchproviene de procpsDebian. La fuente oficial no tiene --exec. El paquete en Debian (y derivados que incluyen Ubuntu) agrega la opción en un parche específico de Debian ( watch_exec_beep.patch; es el "parche de ejecución de Mortys watch" del error # 410967 ). Gentoo puede haber adoptado un parche similar.
Gilles 'SO- deja de ser malvado'