web-dev-qa-db-fra.com

Comment convertir une variable de tableau bash en une chaîne délimitée par des nouvelles lignes?

Je veux écrire une variable de tableau bash dans un fichier, avec chaque élément sur une nouvelle ligne. Je pourrais le faire avec une boucle for, mais existe-t-il une autre façon (plus simple) de joindre les éléments avec \n?

47
ACyclic

Voici un moyen qui utilise l’extension du paramètre bash et sa variable spéciale IFS.

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

Nous utilisons un sous-shell pour éviter d'écraser la valeur de IFS dans l'environnement actuel. Dans ce sous-shell, nous modifions ensuite la valeur de IFS pour que le premier caractère soit une nouvelle ligne (en utilisant $'...' citant). Enfin, nous utilisons des paramètres de développement pour imprimer le contenu du tableau en un seul mot; chaque élément est séparé par le premier caractère de IFS.

Pour capturer une variable:

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

Si votre bash est suffisamment nouveau (4.2 ou ultérieur), vous pouvez (et devriez) continuer à utiliser printf avec l'option -v:

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

Dans les deux cas, vous pouvez ne pas vouloir la nouvelle ligne finale dans var. Pour l'enlever:

$ var=${var%?}    # Remove the final character of var
52
chepner

Vous pouvez utiliser printf pour imprimer chaque élément du tableau sur sa propre ligne:

 $ System=('s1' 's2' 's3' 's4 4 4')
 $ printf "%s\n"  "${System[@]}"
s1
s2
s3
s4 4 4
26
rush
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[@]}"

c'est tout ce que je peux rappeler jusqu'à présent.

6
Meow

Les solutions ci-dessus sont à peu près ce qu'elles sont, mais la question initiale demande une sortie dans un fichier:

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

Remarques: 1) 'echo' fournit la nouvelle ligne finale 2) Si bash veut à nouveau lire ce fichier, bas, alors -p peut être la sérialisation désirée.

2
Brian Chrisman

Utiliser pour :

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

Utilisation de history ; notez que cela échouera si vos valeurs contiennent !:

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

Utiliser basename ; notez que cela échouera si vos valeurs contiennent /:

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

Utiliser shuf ; notez que les résultats risquent de ne pas apparaître dans l'ordre:

shuf -e "${alpha[@]}"
2
Steven Penny