Quebrando um comando que inclui aspas simples e duplas para outro comando


10

Eu aprendi recentemente sobre o relógio , mas estou tendo problemas para fazê-lo funcionar com comandos relativamente sofisticados.

Por exemplo, eu gostaria de pedir watchpara executar o seguinte comando a zshcada três segundos * :

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

como você pode ver, a linha acima inclui aspas simples, aspas duplas, entre outros caracteres especiais.

Então eu tentei:

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

mas então eu tenho:

nenhuma correspondência encontrada para x em! @ # $ # ....; feito

Eu tentei outras combinações sem sucesso. Aqui está uma dessas tentativas:

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

o que também resulta em um erro semelhante.

Alguma idéia de como fazer isso funcionar?


* Eu também estaria interessado em soluções que funcionam embash

Respostas:


16

Dica geral: se você tiver dois níveis de aninhamento, evite usar aspas simples no comando interno e use aspas simples ao redor do comando externo.

Dica adicional: não use backticks - `…` - para executar o código, use em $(…)torno dele. Parênteses em dólar são praticamente DWIM ('Faça o que eu quero dizer') quando se trata de aspas aninhadas; as aspas posteriores têm regras arcanas e dependentes do shell.

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

Se você precisar de aspas simples dentro de um comando de aspas simples, poderá usar '\''. Pense nesses quatro caracteres como a maneira de citar uma aspas simples entre aspas simples, embora tecnicamente isso seja construído como final da sequência de aspas simples, adicione uma aspas simples literal e inicie uma nova sequência de aspas simples (ainda anexada à palavra atual).

Para casos mais complexos, conte meticulosamente as aspas ou defina variáveis ​​temporárias.

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 resposta não é específica para zsh. O Zsh não traz nada de importante aqui. Você pode economizar um pouco de citação porque não há necessidade de aspas duplas nas substituições de comandos e, às vezes, existem maneiras de usar built-ins em vez de comandos externos que reduzem as necessidades de citação, mas os problemas subjacentes são os mesmos de outros shells.

Ah, e a propósito, observe que watcho comando será executado sh, não no zsh. Se você deseja executar o comando no zsh, é necessário executar

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

no Debian / Ubuntu e

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

(ainda mais citando!) em outros lugares.


Obrigado @Gilles. Isso foi muito útil. Curiosamente, watchele não vem com as opções -xnem -cna minha máquina. Procurei on-line e não encontrei nenhuma página de manual que os mencionasse. O que essas opções fazem?
Amelio Vazquez-Reina

11
O @intrpc -xdiz watchpara não passar o comando através de um shell. Acabei de descobrir que isso é específico para o Debian / Ubuntu, mesmo que não seja indicado como tal. O -cé passado para zsh, não para watch.
Gilles 'SO- stop be evil'

@Gilles As opções -xe -execexistem no meu watch(no gentoo), então isso definitivamente não é específico do Debian. Talvez você tenha comparado com alguma outra versão do watch? O meu vem do pacote procps .
rozcietrzewiacz

11
@rozcietrzewiacz também watchvem do procpsDebian. A fonte oficial não tem --exec. O pacote no Debian (e derivados, incluindo o Ubuntu) adiciona a opção em um patch específico do Debian ( watch_exec_beep.patché o "patch do Mortys watch exec" do bug # 410967 ). O Gentoo pode ter adotado um patch semelhante.
Gilles 'SO- stop be evil'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.