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 \n
không?
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 \n
không?
Câu trả lời:
Đây là một cách sử dụng mở rộng tham số bash và IFS
biế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ị IFS
trong môi trường hiện tại. Trong phần con đó, sau đó chúng tôi sửa đổi giá trị IFS
sao 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 printf
với -v
tù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
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.
$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
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.
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.
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[@]}"
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}}"
}
$ 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
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
delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}" # yields one:two_three