Como fazer expansões de múltiplas chaves sem explosão combinatória?

4

Costumo usar a expansão de chave na linha de comando, porque é útil.

Exemplo

{foo,bar}

expande para:

foo bar

A expansão de várias chaves também se expande, por exemplo:

{foo,bar}Q{foo,bar}

se expande para:

fooQfoo fooQbar barQfoo barQbar

Este é o comportamento esperado, onde as expansões de chaves são usadas em ordem.

Minha pergunta

Agora, gostaria que a saída de qualquer expansão de chave (ou outro truque de linha de comando curto) fosse:

fooQfoo barQbar

Nota: estou usando bash 3.2

    
por Bernhard 02.09.2013 / 09:08

2 respostas

4

Eu não consegui descobrir como fazer isso usando apenas chaves. Eu também não vejo uma maneira de conseguir isso, então, a menos que alguém mais inteligente do que eu possa imaginar, eu diria que não é possível.

Como alternativa

Dados de amostra

$ tree
.
|-- dir1
|   |-- file1
|   '-- file2
'-- dir2
    |-- file1
    '-- file2

Exemplos

$ seq 2 | xargs -i{} echo dir{}/file{}
dir1/file1
dir2/file2

Isso pode ser colocado em um comando como este:

$ echo $(seq 2 | xargs -i{} echo dir{}/file{})
dir1/file1 dir2/file2

ou isto:

$ ls $(seq 2 | xargs -i{} echo dir{}/file{})
dir1/file1  dir2/file2

ou isto:

$ ls -l $(seq 2 | xargs -i{} echo dir{}/file{})
-rw-rw-r-- 1 saml saml 0 Sep  2 03:18 dir1/file1
-rw-rw-r-- 1 saml saml 0 Sep  2 03:31 dir2/file2

Por que as chaves não podem fazer isso

Se você olhar seu exemplo original:

{foo,bar}Q{foo,bar}

A maneira como isso é expandido é a seguinte:

fooQfoo fooQbar barQfoo barQbar

O mecanismo que expandiu isso é chamado de Produto cartesiano .

Por exemplo:

$ echo {A,B}{X,Y,Z}
AX AY AZ BX BY BZ

Ou isto:

$ echo {M,N}-{A,B}{X,Y,Z}
M-AX M-AY M-AZ M-BX M-BY M-BZ N-AX N-AY N-AZ N-BX N-BY N-BZ

Não há como criar um produto cartesiano que resulte em:

fooQfoo barQbar

Você só tem a opção de recorrer a truques como este:

$ echo dir{1,2}/file{2,1}
dir1/file2 dir1/file1 dir2/file2 dir2/file1

E, em seguida, coloque isso em uma matriz de Bash:

$ a=(dir{1,2}/file{2,1})
$ echo ${a[@]:1:2}
dir1/file1 dir2/file2

A outra opção seria algum "outro método" como o que eu discuti anteriormente (usando xargs ) por exemplo.

Referências

por 02.09.2013 / 09:32
3

Eu concordo com slm; Eu nunca vi uma maneira de fazer isso apenas com a expansão de chaves.

No entanto, usando o exemplo na pergunta, acho que a maneira mais simples de obter o resultado desejado é usar um loop, em vez de expandir a chave e pós-processamento adicional:

$ echo $(for X in foo bar;do echo ${X}Q${X};done)
fooQfoo barQbar
    
por 02.09.2013 / 19:57