Você pode forçar outra rodada de avaliação com eval
, mas isso não é realmente necessário. (E eval
começa a ter sérios problemas no momento em que seus nomes de arquivos contêm caracteres especiais como $
.) O problema não é com globbing, mas com a expansão til.
Globbing acontece após expansão da variável, se a variável não estiver marcada, como aqui (*) :
$ x="/tm*" ; echo $x
/tmp
Então, na mesma linha, isso é semelhante ao que você fez e funciona:
$ mkdir -p ~/public/foo/ ; touch ~/public/foo/x.launch
$ i="$HOME/public/*"; j="*.launch"; k="$i/$j"
$ echo $k
/home/foo/public/foo/x.launch
Mas com o til isso não acontece:
$ i="~/public/*"; j="*.launch"; k="$i/$j"
$ echo $k
~/public/*/*.launch
Isso é claramente documentado para o Bash:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, ...
A expansão de til ocorre antes da expansão da variável, de modo que as propriedades dentro das variáveis não são expandidas. A solução fácil é
para usar $HOME
ou o caminho completo.
(* globs de expansão de variáveis geralmente não é o que você quer)
Outra coisa:
Quando você percorre os padrões, como aqui:
exclude="foo *bar"
for j in $exclude ; do
...
observe que, como $exclude
não é citada, ela é dividida e também é globalizada nesse momento. Portanto, se o diretório atual contiver algo que corresponda ao padrão, ele será expandido para isso:
$ i="$HOME/public/foo"
$ exclude="*.launch"
$ touch $i/real.launch
$ for j in $exclude ; do # split and glob, no match
echo "$i"/$j ; done
/home/foo/public/foo/real.launch
$ touch ./hello.launch
$ for j in $exclude ; do # split and glob, matches in current dir!
echo "$i"/$j ; done
/home/foo/public/foo/hello.launch # not the expected result
Para resolver isso, use uma variável de matriz em vez de uma string dividida:
$ exclude=("*.launch")
$ exclude+=("something else")
$ for j in "${exclude[@]}" ; do echo "$i"/$j ; done
/home/foo/public/foo/real.launch
/home/foo/public/foo/something else
Como um bônus adicional, as entradas de matriz também podem conter espaços em branco sem problemas com divisão.
Algo semelhante pode ser feito com find -path
, se você não se importar com o nível de diretório dos arquivos de destino. Por exemplo. para encontrar qualquer caminho que termine em /e2e/*.js
:
$ dirs="$HOME/public $HOME/private"
$ pattern="*/e2e/*.js"
$ find $dirs -path "$pattern"
/home/foo/public/one/two/three/e2e/asdf.js
Precisamos usar $HOME
em vez de ~
pelo mesmo motivo de antes e $dirs
precisa ser excluído da linha de comando find
para que seja dividido, mas $pattern
deve ser citado assim não é expandido acidentalmente pelo shell.
(Eu acho que você poderia brincar com -maxdepth
no GNU para limitar a profundidade da busca, se você se importa, mas isso é um pouco diferente).