STDOUT como argumento no bash / Makefile e manipula o espaço corretamente

1

Esta é mais uma prática mental com a sintaxe bash. Gostaria de convidá-lo a considerar isso como um quebra-cabeça, para que possamos resolver isso juntos. Ou como um desafio para entender o bash.

O problema

Por exemplo, eu tenho 3 arquivos em uma pasta ./etc :

  • %código%
    • ./etc
    • foo.txt.example
    • bar.txt.example (sim, há espaço neste arquivo)

Eu construí o alvo para fazer este alvo, baseado nos arquivos acima, funciona:

make "etc/foo.txt"
make "etc/bar.txt"
make "etc/hello world.txt"

Portanto, em teoria, posso construir um comando como este para executar todos os alvos:

make "etc/foo.txt" "etc/bar.txt" "etc/hello world.txt"

Aí vem minha pergunta: Você pode criar um script bash que pesquise todos os hello world.txt.example nomes de arquivos e construir o comando acima?

Requisito

  1. A resposta precisa estar no formato de um comando bash ou de uma definição de destino preferível do Makefile;
  2. Ele precisa ser executado na maioria dos ambientes Linux por padrão. Não deve exigir a instalação de pacotes incomuns.

O que eu tentei

Eu já descobri uma maneira no Makefile para obter todos os nomes de arquivos acima:

txt:
    for fn in "etc/*.txt.example"; do \
        echo "etc/$$(basename -s ".example" "$$fn")"; \
    done

O que basicamente significa rodar isso no bash:

for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done

que fornece a seguinte saída:

etc/foo.txt
etc/bar.txt
etc/hello world.txt

Se você usar a saída deste loop como entrada de outro comando, o comando parece tratar todo o espaço ./etc/*.txt.example como separador de argumentos. Então isso:

make $(for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done)

é praticamente isso:

make "etc/foo.txt" "etc/bar.txt" "etc/hello" "world.txt"

Existe uma maneira de transformar a saída do loop em um argumento que preserve adequadamente os espaços?

    
por Koala Yeung 21.02.2017 / 12:13

3 respostas

2

Você pode usar matrizes:

# Get all example files in an array
examples=(etc/*.example)
# Strip the .example suffix from every element of the array
make "${examples[@]%.example}"

Ou se você tiver o GNU find, sed e xargs (com suporte a nul-delimiter, isto é):

find etc -iname '*.example' -print0 | sed -z 's/\.example$//' | xargs -0 make
    
por 21.02.2017 / 12:21
2

Criando uma lista delimitada por nul de nomes de arquivos e passando-os para make via xargs :

for name in /etc/*.txt.example; do
    printf '%s
for name in /etc/*.txt.example; do
    printf '%s%pre%' "${name%.example}"
done | xargs -0 make
' "${name%.example}" done | xargs -0 make
    
por 21.02.2017 / 12:25
0

Primeiro, crie os arquivos de exemplo e, em seguida, crie

set etc/*.tbl.example
N="shift $#"
for arg
do
   $N; N=;
   set X ${1+"$@"} "$(expr "$arg" '\(.*\).example')"; shift       
done
# and then...
make ${1+"$@"}
    
por 22.02.2017 / 12:34

Tags