Como faço para converter uma variável de matriz bash em uma string delimitada por novas linhas?

40

Eu quero escrever uma variável de matriz bash para um arquivo, com cada elemento em uma nova linha. Eu poderia fazer isso com um loop for, mas existe outra maneira (mais limpa) de unir os elementos com \n ?

    
por ACyclic 15.08.2012 / 16:41

6 respostas

43

Aqui está uma maneira que utiliza a expansão do parâmetro bash e sua variável especial IFS .

$ System=('s1' 's2' 's3' 's4 4 4')
$ ( IFS=$'\n'; echo "${System[*]}" )

Usamos um subshell para evitar sobrescrever o valor de IFS no ambiente atual. Nesse subshell, modificamos o valor de IFS para que o primeiro caractere seja uma nova linha (usando $'...' quoting). Finalmente, usamos a expansão de parâmetros para imprimir o conteúdo da matriz como uma única palavra; cada elemento é separado pelo primeiro caractere de IFS .

Para capturar uma variável:

$ var=$( IFS=$'\n'; echo "${System[*]}" )

Se o seu bash é novo o suficiente (4.2 ou posterior), você pode (e deve) ainda usar printf com a opção -v :

$ printf -v var "%s\n" "${System[@]}"

Em ambos os casos, você pode não querer a nova linha final em var . Para removê-lo:

$ var=${var%?}    # Remove the final character of var
    
por 16.08.2012 / 15:38
22

Você pode usar printf para imprimir cada item da matriz em sua própria linha:

 $ System=('s1' 's2' 's3' 's4 4 4')
 $ printf "%s\n"  "${System[@]}"
s1
s2
s3
s4 4 4
    
por 15.08.2012 / 17:03
5
awk -v sep='\n' 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"

ou

perl -le 'print join "\n",@ARGV' "${arr[@]}"

ou

python -c 'import sys;print "\n".join(sys.argv[1:])' "${arr[@]}"

ou

sh -c 'IFS=$'\''\n'\'';echo "$*"' '' "${arr[@]}"

ou

lua <(echo 'print(table.concat(arg,"\n"))') "${arr[@]}"

ou

tclsh <(echo 'puts [join $argv "\n"]') "${arr[@]}"

ou

php -r 'echo implode("\n",array_slice($argv,1));' -- "${arr[@]}"

ou

ruby -e 'puts ARGV.join("\n")' "${arr[@]}"

é tudo que posso lembrar até agora.

    
por 22.02.2014 / 05:25
2

As soluções acima são basicamente isso, mas a pergunta original pede a saída para o arquivo:

$ a=(a b c d e)
$ ( IFS=$'\n'; echo "${a[*]}" ) > /tmp/file
$ cat /tmp/file
a
b
c
d
e
$

Notas: 1) 'echo' fornece a nova linha final 2) Se este arquivo apenas for lido pelo bash novamente, então declare -p pode ser a serialização desejada.

    
por 26.08.2014 / 01:03
2

Usando para :

for each in "${alpha[@]}"
do
  echo "$each"
done

Usando o histórico ; observe que isso falhará se seus valores contiverem ! :

history -p "${alpha[@]}"

Usando basename ; observe que isso falhará se seus valores contiverem / :

basename -a "${alpha[@]}"

Usando shuf ; observe que os resultados podem não aparecer em ordem:

shuf -e "${alpha[@]}"
    
por 20.05.2015 / 04:31
-1

printf parece ser a abordagem mais eficiente para criar uma string delimitada a partir de uma matriz:

# create a delimited string; note that printf doesn't put the trailing delimiter
# need to save and restore IFS
# it is prudent to put the whole logic on a single line so as to minimize the risk of future code changes breaking the sequence of saving/restoring of IFS
oldIFS=$IFS; IFS=$'\n'; printf -v var "${arr[*]}"; IFS=$oldIFS

# print string to file; note that the newline is required in the format string because printf wouldn't put a trailing delimiter (which is a good thing)
printf '%s\n' "$var" > file

Uma maneira ainda mais simples de fazer isso é:

delim=$'\n'
printf -v var "%s$delim" "${arr[@]}" # create a delimited string
var="${var%$delim}"                  # remove the trailing delimiter

Exemplo

delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}"                  # yields one:two_three
    
por 25.01.2018 / 19:39

Tags