Làm cách nào để chuyển đổi biến mảng bash thành chuỗi được phân tách bằng dòng mới?


50

Tôi muốn viết ra một biến mảng bash vào một tệp, với mỗi phần tử trên một dòng mới. Tôi có thể làm điều này với một vòng lặp for, nhưng có cách nào khác (sạch hơn) để tham gia các phần tử với \nkhông?

Câu trả lời:


59

Đây là một cách sử dụng mở rộng tham số bash và IFSbiến đặc biệt của nó .

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

Chúng tôi sử dụng một lớp con để tránh ghi đè giá trị IFStrong môi trường hiện tại. Trong phần con đó, sau đó chúng tôi sửa đổi giá trị IFSsao cho ký tự đầu tiên là một dòng mới (sử dụng $'...'trích dẫn). Cuối cùng, chúng tôi sử dụng mở rộng tham số để in nội dung của mảng dưới dạng một từ đơn; mỗi phần tử được phân tách bằng ký tự đầu tiên của IFS.

Để nắm bắt đến một biến:

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

Nếu bash của bạn đủ mới (4.2 trở lên), bạn vẫn có thể (và nên) sử dụng printfvới -vtùy chọn:

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

Trong cả hai trường hợp, bạn có thể không muốn dòng mới cuối cùng trong var. Để loại bỏ nó:

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

Cảm ơn, có cách nào để xuất cái này sang một biến không?
ACyclic

Cập nhật để hiển thị làm thế nào để nắm bắt đến một biến.
chepner

2
Không nên là ví dụ cuối cùng var=${var%?}thay thế? Đây không phải là biểu thức chính quy, vì vậy .sẽ chỉ khớp với một ký tự dấu chấm.
musiphil

Cần trích dẫn tên biến mảng:$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
Seff

28

Bạn có thể sử dụng printfđể in từng mục mảng trên dòng riêng của mình:

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

hoặc là

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

hoặc là

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

hoặc là

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

hoặc là

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

hoặc là

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

hoặc là

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

hoặc là

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

đó là tất cả những gì tôi có thể nhắc nhở cho đến nay.


2

Các giải pháp trên có khá nhiều, nhưng câu hỏi ban đầu yêu cầu đầu ra cho tệp:

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

Lưu ý: 1) 'echo' cung cấp dòng mới cuối cùng 2) Nếu tệp này sẽ được đọc lại bằng bash, thì khai báo -p có thể là tuần tự hóa muốn.


2

Sử dụng cho :

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

Sử dụng lịch sử ; lưu ý điều này sẽ thất bại nếu giá trị của bạn chứa !:

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

Sử dụng tên cơ sở ; lưu ý điều này sẽ thất bại nếu giá trị của bạn chứa /:

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

Sử dụng shuf ; lưu ý rằng kết quả có thể không được đưa ra theo thứ tự:

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

0

Của tôi , chỉ sử dụng các nội dung Bash, mà không biến đổi 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}}"
}

Thí dụ

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

Bạn cũng có thể sử dụng bất kỳ dấu phân cách nào:

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

-1

printf dường như là cách tiếp cận hiệu quả nhất để tạo một chuỗi phân tách từ một mảng:

# 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

Một cách thậm chí đơn giản hơn để làm điều này là:

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

Thí dụ

delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}"                  # yields one:two_three

2
Downvoter, xin vui lòng bình luận những gì sai ở đây.
tiền mã hóa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.