I want to write out a bash array variable to a file, with each element on a new line. I could do this with a for loop, but is there another (cleaner) way to join the elements with \n?


Here's a way that utilizes bash parameter expansion and its IFS special variable.

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

We use a subshell to avoid overwriting the value of IFS in the current environment. In that subshell, we then modify the value of IFS so that the first character is a newline (using $'...' quoting). Finally, we use parameter expansion to print the contents of the array as a single word; each element is separated by the first charater of IFS.

To capture to a variable:

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

If your bash is new enough (4.2 or later), you can (and should) still use printf with the -v option:

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

In either case, you may not want the final newline in var. To remove it:

$ var=${var%?}    # Remove the final character of var
  • Thanks, is there a way to output this to a variable? – ACyclic Aug 16 '12 at 16:26
  • Updated to show how to capture to a variable. – chepner Aug 16 '12 at 16:34
  • 2
    Shouldn't the last example be var=${var%?} instead? This is not a regular expression, so . will match only a period character. – musiphil Sep 13 '13 at 17:49
  • Need quotes the array variable name: $ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third – Seff Jun 16 at 4:23

You can use printf to print each array item on its own line:

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


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


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


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


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


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


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


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

that's all I can remind so far.


Above solutions are pretty much it, but the original question asks for output to file:

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

Notes: 1) 'echo' provides the final newline 2) If this file will just be read in by bash again, then declare -p may be the serialization wanted.


Using for:

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

Using history; note this will fail if your values contain !:

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

Using basename; note this will fail if your values contain /:

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

Using shuf; note that results might not come out in order:

shuf -e "${alpha[@]}"

My take, using only Bash builtins, without mutating 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}}"


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

You can also use any separator:

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

printf seems to be the most efficient approach for creating a delimited string from an array:

# 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

An even simpler way to do this is:

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


arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}"                  # yields one:two_three
  • 2
    Downvoter, please comment what is wrong here. – codeforester Jan 26 '18 at 13:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.