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?

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

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

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.


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.


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[@]}"

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

-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

2
En bas, s'il vous plaît commentez ce qui ne va pas ici.
Codeforester
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.