Вопрос или проблема
Недавно я узнал о 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'
Пояснения:
-
Одинарные кавычки: Использование одинарных кавычек вокруг всей команды позволяет оболочке интерпретировать строку как единое целое без необходимости экранирования внутренних двойных кавычек.
-
Конструкция $(…): Эта конструкция позволяет выполнять команды внутри команд, что делает код более читаемым и понятным. Она также упрощает управление кавычками.
-
Экранирование переменных: Обратите внимание, что мы экранируем переменную
"$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
. Не забывайте экспериментировать с различными способами вызова команд и приятного кодирования!