Makefile, colchetes sqare embutidos, expansão de variáveis e substituição de comandos

0

Para abraçar o princípio DRY (Don't Repeat Yourself), às vezes preciso compartilhar partes de comandos do shell em um Makefile . Então há uma receita em algum lugar nesse arquivo como:

shell=/bin/bash
# …
.ONESHELL:
run:
    # Create bash sub-shell «cmd» var, holding a built-in test as a string
    @cmd='[ $$(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]'
    # "$$" tells make to escape the dollar sign. So echoing …
    @echo "$$cmd"
    # gives «[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ]» as I expected
    # I need this variable to be expanded and interpreted as a real
    # built-in square bracket test, so I wrote
    @$$cmd && echo "Pass ! do more magical things …" || true

Eu esperava que fizesse escapar $ sign $$cmd$cmd que por sua vez seria expandido dentro do contexto bash para o teste de colchetes string sem aspas ... ?
Mas recebo um erro em vez de /bin/bash: line 2: [: too many arguments

Alguém tem uma ideia de por que esse erro está sendo levantado?
Por que bash não recebe o teste de suporte que eu espero?
[ $(grep -iE _dev </etc/hosts | wc -l) -eq 0 ] && echo "Pass!"

Obrigado.

    
por Stphane 21.10.2017 / 00:37

2 respostas

0

Substituições de comando e variável no shell ocorrem após decidir sobre limites de comando e analisar redirecionamentos (e atribuições). Você pode colocar um nome de programa e / ou argumentos em uma variável e substituí-los, mas não pipes ou redirecionamento ou outras substituições incluindo $( command ) ou atribuições ou palavras-chave shell como if e for .

Nesse caso, você pode eliminar o pipe, o wc e a substituição alterando o comando e revertendo o teste:

cmd='grep -qi _dev /etc/hosts' # note file as argument not redirection
$$cmd || do_blah

em que o comando grep substituído falha (silenciosamente) se ele não encontrar qualquer correspondência no arquivo e, se falhar, do_blah será executado.

Em geral, para usar a sintaxe shell (não apenas argumentos do programa) em um valor substituto, você deve usar eval para executar o valor (ou valores) substituído, ou então executar um shell filho como sh -c "$$cmd" (substituir outro shell se necessário, dependendo do ambiente e / ou comando).

    
por 21.10.2017 / 10:59
0

Um Makefile não é um script de shell. A coisa toda poderia ser mais simples e limpa como

#!/bin/sh
set -e
grep -q -iE _dev /etc/hosts
echo pass
...
    
por 21.10.2017 / 01:25