Bagaimana cara mengonversi variabel array bash ke string yang dibatasi dengan baris baru?

50

Saya ingin menulis variabel array bash ke file, dengan setiap elemen pada baris baru. Saya bisa melakukan ini dengan for for loop, tetapi apakah ada cara lain (bersih) untuk bergabung dengan elemen \n?

Asiklik
sumber

Jawaban:

59

Inilah cara yang memanfaatkan ekspansi parameter bash dan IFSvariabel khususnya.

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

Kami menggunakan subkulit untuk menghindari menimpa nilai IFSdalam lingkungan saat ini. Dalam subkulit itu, kami kemudian memodifikasi nilai IFSsehingga karakter pertama adalah baris baru (menggunakan $'...'kutipan). Akhirnya, kami menggunakan ekspansi parameter untuk mencetak isi array sebagai satu kata; setiap elemen dipisahkan oleh karakter pertama dari IFS.

Untuk menangkap ke suatu variabel:

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

Jika pesta Anda cukup baru (4.2 atau yang lebih baru), Anda dapat (dan harus) masih menggunakan printfdengan -vpilihan:

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

Dalam kedua kasus itu, Anda mungkin tidak ingin baris baru final masuk var. Untuk menghapusnya:

$ var=${var%?}    # Remove the final character of var
chepner
sumber
Terima kasih, apakah ada cara untuk menampilkan ini ke variabel?
ACyclic
Diperbarui untuk menunjukkan cara menangkap ke suatu variabel.
chepner
2
Bukankah seharusnya contoh terakhir var=${var%?}? Ini bukan ekspresi reguler, jadi .hanya akan cocok dengan karakter titik.
musiphil
Perlu mengutip nama variabel array:$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
Seff
28

Anda dapat menggunakan printfuntuk mencetak setiap item array pada barisnya sendiri:

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

atau

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

atau

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

atau

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

atau

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

atau

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

atau

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

atau

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

itu yang bisa saya ingatkan sejauh ini.

meong
sumber
2

Solusi di atas cukup banyak, tetapi pertanyaan aslinya meminta output ke file:

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

Catatan: 1) 'echo' memberikan baris terakhir akhir 2) Jika file ini hanya akan dibaca oleh bash lagi, maka menyatakan -p mungkin serialisasi yang diinginkan.

Brian Chrisman
sumber
2

Menggunakan untuk :

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

Menggunakan sejarah ; perhatikan ini akan gagal jika nilai Anda mengandung !:

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

Menggunakan nama bas ; perhatikan ini akan gagal jika nilai Anda mengandung /:

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

Menggunakan shuf ; perhatikan bahwa hasilnya mungkin tidak keluar secara berurutan:

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

Pilihan saya , hanya menggunakan Bash bawaan, tanpa bermutasi 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}}"
}

Contoh

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

Anda juga dapat menggunakan pemisah apa pun:

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

printf tampaknya menjadi pendekatan yang paling efisien untuk membuat string yang dibatasi dari 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

Cara yang lebih sederhana untuk melakukan ini adalah:

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

Contoh

delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}"                  # yields one:two_three
codeforester
sumber
2
Downvoter, tolong beri komentar apa yang salah di sini.
codeforester