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

50

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 un autre moyen (plus propre) de joindre les éléments \n?

ACyclique
la source

Réponses:

59

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

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

Nous utilisons un sous-shell pour éviter d'écraser la valeur de IFSdans l'environnement actuel. Dans ce sous-shell, nous modifions ensuite la valeur de IFSafin que le premier caractère soit une nouvelle ligne (en utilisant des $'...'guillemets). Enfin, nous utilisons les paramètres de développement pour imprimer le contenu du tableau sous la forme d’un mot unique; 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) toujours utiliser printfavec l' -voption:

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

Dans les deux cas, vous ne voudrez peut-être pas la nouvelle ligne finale var. Pour l'enlever:

$ var=${var%?}    # Remove the final character of var
Chepner
la source
Merci, y at-il un moyen de sortir ceci dans une variable?
ACyclique
Mise à jour pour montrer comment capturer une variable.
Chepner
2
Le dernier exemple ne devrait-il pas être à la var=${var%?}place? Ce n'est pas une expression régulière et .ne correspondra donc qu'à un point.
musiphil
Need cite le nom de la variable de tableau:$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
Seff
28

Vous pouvez utiliser printfpour 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
se ruer
la source
7
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.

Miaou
la source
2

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
$

Notes: 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.

Brian Chrisman
la source
2

Utilisant pour :

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

Utiliser l' histoire ; notez que cela échouera si vos valeurs contiennent !:

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

Utiliser le nom de base ; notez que cela échouera si vos valeurs contiennent /:

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

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

shuf -e "${alpha[@]}"
Steven Penny
la source
0

Ma prise , en utilisant uniquement les commandes intégrées de Bash, sans mutation IFS:

# $1  separator
# $2… strings
join_strings () {
    declare separator="$1";
    declare -a args=("${@:2}");
    declare result;
    printf -v result '%s' "${args[@]/#/$separator}";
    printf '%s' "${result:${#separator}}"
}

Exemple

$ join_strings $'\n' "a b c" "d e f" "g h i"
a b c
d e f
g h i

Vous pouvez également utiliser n'importe quel séparateur:

$ join_strings '===' "a b c" "d e f" "g h i"
a b c===d e f===g h i
jcayzac
la source
-1

printf semble être l’approche la plus efficace pour créer une chaîne délimitée à partir d’un tableau:

# 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

Une façon encore plus simple de faire ceci est:

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

Exemple

delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}"                  # yields one:two_three
codeforester
la source
2
En bas, s'il vous plaît commentez ce qui ne va pas ici.
Codeforester