usa linhas como argumentos em uma chamada (xargs-like)

1

Eu tenho uma função que imprime várias linhas que eu quero usar como argumentos para outra função:

lsx() {
    echo 1 is one
    echo 2 are two
}

somefun() {
    for arg in "$@"; do
        echo "arg='$arg'"
    done
}

Como posso "elegantemente" chamar somefun() com linhas de lsx() como argumentos?

O que eu faço agora é percorrer as linhas usando while , armazenando linhas na matriz, mas isso parece feio e funciona demais. (Edit: Isso não funciona devido ao while + subshell) . Eu acho que deveria haver uma maneira simples (até portável?), Mas não é possível criar uma.

(Se somefun fosse um comando externo, eu usaria xargs , mas não é.)

    
por Alois Mahdal 25.08.2016 / 22:00

2 respostas

4

Sem xargs

$ ( IFS=$'\n'; somefun $(lsx) )
arg='1 is one'
arg='2 are two'

O subshell é usado para que a alteração para IFS seja local, não global.

Limitação : Isso submete a saída de lsx à expansão do nome do caminho, o que pode ou não ser um problema.

Com xargs

Para acessar uma função de shell com xargs, precisamos executar um shell. Para ter acesso a somefun em um shell filho, primeiro precisamos exportá-lo. Assim:

$ export -f somefun
$ lsx | xargs -d'\n' bash -c 'somefun "$@"' SomeFun
arg='1 is one'
arg='2 are two'

O primeiro argumento para bash é atribuído a $0 e serve como o nome do programa em mensagens de erro. Esta pode ser uma palavra arbitrária. Aqui, usamos SomeFun .

Exemplos dos problemas de expansão do nome do caminho

$ lsx() { echo '1 is one*'; echo '2 are two*'; }
$ touch '1 is one'{1..3} two{a..c}
$ ( IFS=$'\n'; somefun $(lsx) )
arg='1 is one1'
arg='1 is one2'
arg='1 is one3'
arg='2 are two*'

Como você pode ver, a primeira linha de saída foi expandida em três linhas.

O shell primeiro executa divisão de palavras na saída de $(lsx) . Como o IFS é definido como um caractere de nova linha, a saída é dividida em linhas. O shell executa então a expansão do nome do caminho. Como existem arquivos que correspondem ao glob 1 is one* , esse glob é expandido em uma lista desses nomes. Em nosso exemplo, não há arquivos que correspondam ao glob 2 is two* e, portanto, que glob não seja expandido. (No IFS padrão, 2 is two* teria sido dividido em três palavras e o terceiro corresponderia aos arquivos twoa , twob e twoc .)

A abordagem xargs evita a expansão do nome do caminho:

$ export -f somefun
$ lsx | xargs -d'\n' bash -c 'somefun "$@"' SomeFun
arg='1 is one*'
arg='2 are two*'
    
por 25.08.2016 / 22:09
2

Solução trivial:

IFS="
"
somefun $(lsx)
    
por 25.08.2016 / 22:08