Como ler de um tubo mantendo os parâmetros posicionais?

4

Estou escrevendo um pequeno script que gostaria de fazê-lo funcionar a partir de uma entrada canalizada ou então dos argumentos de linha de comando.

my_function() {
  for i in "$@"; do
    echo "$i"
    echo -----
  done
}

if [ -t 0 ]; then
  my_function "$@"    # command-line arguments
else
  my_function $(cat)  # pipe
fi

Estas opções funcionam:

$ my_script 1 2 3 4
$ echo 1 2 3 4 | my_script
1
-----
2
-----
3
-----
4
-----

Isso também funciona bem:

$ my_script 1 "2 3" 4
1
-----
2 3
-----
4
-----

O problema surge quando tento manter os parâmetros posicionais de um canal:

$ echo 1 "2 3" 4 | my_script
1
-----
2
-----
3
-----
4
-----
$ echo 1 "'2 3'" 4 | my_script
1
-----
'2
-----
3'
-----
4
-----

Em vez de my_function $(cat) , tentei usar read sem bons resultados, algo como:

read input
my_function $input

Alguma idéia sobre isso? Eu sei que a divisão de palavras é difícil.

    
por Arturo Herrero 01.05.2017 / 21:51

1 resposta

3

Dê uma olhada nesta técnica com o bash 4.4:

function myf { 
  if ! [ -t 0 ];then 
    declare -a args=\($(</dev/stdin)\);
    set -- "${args[@]}"; 
  fi;
  for i in "$@";do 
    echo "$i";
    echo -----;
  done 
}

Teste:

$ function myf { if ! [ -t 0 ];then declare -a args=\($(</dev/stdin)\);set -- "${args[@]}"; fi;for i in "$@";do echo "$i";echo -----;done }
$ myf 1 "2 3" 4
1
-----
2 3
-----
4
-----

$ echo $'1 "2 3" 4'|myf
1
-----
2 3
-----
4
-----

O mesmo resultado pode ser alcançado também com:

$ echo 1 \"2 3\" 4 |myf
$ echo 1 "'2 3'" 4 |myf

Mas echo 1 "2 3" 4 não vai funcionar, porque as aspas duplas são ignoradas pelo bash nessa sintaxe:

$ echo 1 "2 3" 4
1 2 3 4
    
por 02.05.2017 / 00:18