Оборачивание команды, которая включает одинарные и двойные кавычки для другой команды.

Вопрос или проблема

Недавно я узнал о watch, но у меня возникли проблемы с его использованием в относительно сложных командах.

Например, я хотел бы попросить watch выполнять следующую команду в zsh каждые три секунды*:

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

Как вы можете видеть, приведённая выше строка содержит одиночные кавычки, двойные кавычки и другие специальные символы.

Поэтому я пробовал:

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

Но тогда я получил:

не найден ни один совпадающий x в !@#$# ….; done

Я пробовал другие комбинации, но безуспешно. Вот одна из этих попыток:

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

Что также приводит к аналогичной ошибке.

Есть идеи, как заставить это работать?


*Мне также интересны решения, которые работают в bash

Общий совет: если у вас два уровня вложенности, избегайте использования одиночных кавычек во внутренней команде и используйте одиночные кавычки вокруг внешней команды.

Дополнительный совет: не используйте обратные кавычки – `…` – для выполнения кода, вместо этого используйте $(…). Долларовые скобки практически делают все за вас (‘Do what I mean’) в контексте вложенных кавычек; обратные кавычки имеют загадочные, зависящие от оболочки правила.

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

Если вам нужны одиночные кавычки внутри команды, заключённой в одиночные кавычки, вы можете использовать '\''. Считайте эти четыре символа способом заключить одиночную кавычку внутри одиночных кавычек, хотя технически говоря, это устроено так, что заканчивается строка в одиночных кавычках, добавляется буквальная одиночная кавычка и начинается новая строка в одиночных кавычках (по-прежнему добавленная к текущему слову).

Для более сложных случаев либо старательно считайте кавычки, либо определяйте временные переменные.

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

Этот ответ не зависит от zsh. Zsh не приносит ничего важного в этом отношении. Вы можете сэкономить немного на кавычках, потому что нет необходимости в двойных кавычках вокруг замены команды, а иногда есть способы использовать встроенные команды вместо внешних, что уменьшает потребность в кавычках, но основные проблемы те же, что и в других оболочках.

О, и кстати, обратите внимание, что watch будет выполнять вашу команду в sh, а не в zsh. Если вы хотите выполнить команду в zsh, вам нужно выполнить

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

в Debian/Ubuntu, а также

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

(даже больше кавычек!) в других местах.

Ответ или решение

Как использовать команду watch с сложными командами в zsh

Когда вы работаете с командой watch в zsh, особенно с командами, которые содержат как одинарные, так и двойные кавычки, возникают некоторые трудности. В этой статье мы разберем, как правильно обернуть команду, чтобы избежать ошибок и проблем с экранированием символов.

Проблема и ее решение

Проблема заключается в том, что команда, которую вы хотите использовать с watch, включает специальные символы и разные типы кавычек. Это может привести к тому, что оболочка не сможет правильно интерпретировать вашу команду. Например, если вы попытаетесь выполнить следующую команду:

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

Вы столкнетесь с ошибкой, связанной с несовпадением символов. Чтобы решить эту проблему, рекомендуется использовать вывод команд через конструкцию $(...), которая более предпочтительна по сравнению с использованием обратных кавычек.

Обертывание команды

Вот правильный способ обернуть сложную команду для использования с watch:

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

Пояснения:

  1. Одинарные кавычки: Использование одинарных кавычек вокруг всей команды позволяет оболочке интерпретировать строку как единое целое без необходимости экранирования внутренних двойных кавычек.

  2. Конструкция $(…): Эта конструкция позволяет выполнять команды внутри команд, что делает код более читаемым и понятным. Она также упрощает управление кавычками.

  3. Экранирование переменных: Обратите внимание, что мы экранируем переменную "$x", чтобы избежать потенциальных проблем, если переменная содержит пробелы или специальные символы.

Использование команды группировки

В случае, если вам необходимо использовать одинарные кавычки внутри строки, охватываемой одинарными кавычками, можно использовать следующий трюк:

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

Здесь мы закрываем строку, добавляем экранированные одинарные кавычки и снова открываем строку. Это позволяет корректно вставить одинарные кавычки в уже существующую строку, сохраняя при этом правильную интерпретацию другими кавычками.

Вызов команд в zsh

Следует помнить, что watch по умолчанию выполняет команды в оболочке sh. Если вы хотите запустить команду в zsh, используйте следующие команды:

Для Debian/Ubuntu:

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

Для других систем:

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

Это позволяет вам использовать все функции и возможности оболочки zsh.

Заключение

Правильное использование команд с watch — это вопрос аккуратного обращения с кавычками, интерпретацией команд и выбором нужных конструкций. Используя приведенные рекомендации, вы сможете без проблем выполнять сложные команды с watch в любой shell, включая zsh и bash. Не забывайте экспериментировать с различными способами вызова команд и приятного кодирования!

Оцените материал
Добавить комментарий

Капча загружается...