ฉันจะแปลงตัวแปร bash array เป็นสตริงที่คั่นด้วย newlines ได้อย่างไร


50

ฉันต้องการเขียนตัวแปรอาเรย์ bash ลงในไฟล์โดยแต่ละองค์ประกอบในบรรทัดใหม่ ฉันสามารถทำสิ่งนี้ได้ด้วย for for loop แต่มีวิธีอื่น (สะอาดกว่า) ในการเข้าร่วมองค์ประกอบด้วย\nหรือไม่

คำตอบ:


59

นี่คือวิธีที่ใช้การขยายพารามิเตอร์ bash และIFSตัวแปรพิเศษ

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

เราใช้ subshell เพื่อหลีกเลี่ยงการเขียนทับค่าของIFSในสภาพแวดล้อมปัจจุบัน ในเชลล์ย่อยนั้นเราจะแก้ไขค่าIFSเพื่อให้อักขระตัวแรกเป็นขึ้นบรรทัดใหม่ (โดยใช้การ$'...'อ้างอิง) สุดท้ายเราใช้การขยายพารามิเตอร์เพื่อพิมพ์เนื้อหาของอาร์เรย์เป็นคำเดียว แต่ละองค์ประกอบจะแยกจากกันโดย charater IFSแรกของ

ในการจับภาพไปยังตัวแปร:

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

หากทุบตีของคุณใหม่พอ (4.2 หรือใหม่กว่า) คุณยังสามารถ (และควร) ยังคงใช้printfกับ-vตัวเลือก:

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

varในทั้งสองกรณีที่คุณอาจไม่ต้องการขึ้นบรรทัดสุดท้ายใน หากต้องการลบ:

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

ขอบคุณมีวิธีส่งออกตัวแปรนี้หรือไม่?
วัฏจักร

อัปเดตเพื่อแสดงวิธีจับภาพตัวแปร
chepner

2
ไม่ควรเป็นตัวอย่างสุดท้ายvar=${var%?}แทน? นี่ไม่ใช่นิพจน์ทั่วไปดังนั้น.จะจับคู่เฉพาะอักขระช่วงเวลา
musiphil

ต้องการอัญประกาศชื่อตัวแปรอาเรย์:$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
Seff

28

คุณสามารถใช้printfในการพิมพ์แต่ละรายการอาเรย์ในบรรทัดของตัวเอง:

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

หรือ

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

นั่นคือทั้งหมดที่ฉันสามารถเตือนได้จนถึงตอนนี้


2

การแก้ปัญหาข้างต้นนั้นค่อนข้างสวย แต่คำถามเดิมขอให้เอาท์พุทเป็นไฟล์:

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

หมายเหตุ: 1) 'echo' ให้ขึ้นบรรทัดใหม่สุดท้าย 2) หากไฟล์นี้เพิ่งจะถูกอ่านโดยทุบตีอีกครั้งประกาศ -p อาจต้องการอนุกรม


2

ใช้สำหรับ :

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

ใช้ประวัติศาสตร์ ; โปรดทราบว่าสิ่งนี้จะล้มเหลวหากค่าของคุณมี!:

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

ใช้basename ; โปรดทราบว่าสิ่งนี้จะล้มเหลวหากค่าของคุณมี/:

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

ใช้shuf ; โปรดทราบว่าผลลัพธ์อาจไม่ออกมาตามลำดับ:

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

0

ฉันใช้เวลาโดยใช้ builtins เพียงทุบตีโดยไม่ต้องกรรมวิธี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

คุณสามารถใช้ตัวคั่นใดก็ได้:

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

-1

printf น่าจะเป็นวิธีที่มีประสิทธิภาพมากที่สุดสำหรับการสร้างสตริงที่คั่นจากอาร์เรย์:

# 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

วิธีที่ง่ายกว่าในการทำเช่นนี้คือ:

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

2
Downvoter โปรดแสดงความคิดเห็นว่ามีอะไรผิดปกติที่นี่
codeforester
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.