ฉันจะลบองค์ประกอบออกจากอาร์เรย์ได้อย่างไร


48

unset array[0]เอาองค์ประกอบ แต่ถ้าฉันจะecho ${array[0]}ได้รับค่า Null นอกจากนี้ยังมีวิธีอื่นในการทำเช่นนี้ แต่ถ้าองค์ประกอบของอาร์เรย์มีช่องว่างเช่นด้านล่าง

array[0]='james young'
array[1]='mary'
array[2]='randy orton'

แต่สิ่งเหล่านี้ก็ไม่สามารถทำงานได้เช่นกัน

array=${array[@]:1} #removed the 1st element

ตอนนี้ฉันต้องการอาร์เรย์ใหม่ให้เป็นเหมือน

array[0]='mary'
array[1]='randy orton'

ช่องว่างทำให้เกิดปัญหาหลังจากการกำหนดและอาร์เรย์ที่แท้จริงกลายเป็นเหมือนการทดแทน

array=(mary randy orton)

4
ไม่ช่องว่างไม่ก่อให้เกิดปัญหา แต่ขาดการอ้างอิง
จัดการ

คำตอบ:


68

เพียงใช้ไวยากรณ์ของอาเรย์กับการมอบหมายและพูดตัวแปรของคุณ:

array=("${array[@]:1}") #removed the 1st element

แก้ไขตามคำถามในความคิดเห็น สำหรับ$@คุณสามารถใช้งานได้เช่นนี้:

set -- "${@:2}" #removed the 1st parameter

8
โปรดทราบว่ามันไม่ได้ลบองค์ประกอบที่ 1แต่องค์ประกอบของดัชนี 0 และกำหนดดัชนีใหม่ หากองค์ประกอบแรกอยู่ในดัชนี 12 จะไม่ลบอะไรเลย แต่จะกำหนดดัชนีใหม่เพื่อให้สิ่งที่ครั้งหนึ่งเคยเป็นดัชนี 12 จะกลายเป็นดัชนี 0 ตอนนี้มันอาจจะไม่ใช่ประเด็นที่น่ากังวลในกรณีของ OP แต่ควรจะสังเกต การอ้างอิงในอนาคต. พฤติกรรมจะแตกต่างกันกับzshอาร์เรย์ที่ไม่กระจัดกระจายกับ ksh หรือทุบตี
Stéphane Chazelas

3
สวัสดี @ StephaneChazelas เอกพจน์ของ "ดัชนี" คือ " ดัชนี " ขอบคุณสำหรับความคิดเห็นของคุณ!
Steven Lu

3
@ manatwork - อีกครั้ง: การแก้ไขของคุณ - ทำไมไม่ใช้shift?
don_crissti

1
@don_crissti จุดดี ฉันมุ่งเน้นไปที่ความแตกต่างของการจัดทำดัชนีและไม่ได้คิดเพิ่มเติม นอกจากนี้ยังมีอยู่ในใจสถานการณ์เมื่อคุณต้องการที่จะทิ้งตัวแปรจำนวนรายการเช่นเพื่อให้ตรงกับที่ผ่านมา 3: และarray=("${array[@]: -3}") set -- "${@: -3}"ดังนั้นติดอยู่ที่ดัชนี
จัดการ

1
shift $[$#-3]สำหรับ 3 รายการสุดท้ายนั้นอาจเร็วกว่าสำหรับ$@
Tino

0

สิ่งนี้ทำให้ฉันคิด ปัญหาของ sed / awk / tail ก็คือพวกมันทีละบรรทัด หลังจากที่คุณลบบรรทัดแรกคุณต้องเขียนบรรทัดอื่นจากพื้นที่รูปแบบไปยังไฟล์

  • คุณสามารถใช้คำสั่งต่อไปนี้เพื่อทำสิ่งที่คุณต้องการในไม่กี่วินาที
  • นี้จะเขียนไฟล์ทั้งหมดไปยังอาร์เรย์
  • ลบบรรทัดแรกทิ้งลงในไฟล์

    readarray -t aLargeFile < <(cat largefile)
    echo "${aLargeFile[@]:1}" >largefile
    

เพียงเปลี่ยนเป็นlargefileชื่อไฟล์ของคุณ


ทำไมไม่ใช้sed -i 1d largefileแทน สิ่งนี้ใช้ได้กับไฟล์ที่ใหญ่กว่า RAM + swap
Tino

0

ในการลบองค์ประกอบที่ดัชนีเฉพาะเราสามารถใช้unsetแล้วคัดลอกไปยังอาร์เรย์อื่น unsetไม่จำเป็นต้องใช้เพียงแค่ในกรณีนี้ เพราะunsetไม่ได้ลบองค์ประกอบมันเพียงแค่ตั้งค่าสตริงเป็นดัชนีเฉพาะในอาร์เรย์

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
unset 'arr[1]'
declare -a arr2=()
i=0
for element in ${arr[@]}
do
    arr2[$i]=$element
    ((++i))
done
echo ${arr[@]}
echo "1st val is ${arr[1]}, 2nd val is ${arr[2]}"
echo ${arr2[@]}
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

ผลผลิตคือ

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd

-1
#!/bin/bash

q=( one two three four five )

echo -e "
  (remove) { [:range:] } <- [:list:]
                | [:range:] => return list with range removed range is in the form of [:digit:]-[:digit:]
"

function remove {
  if [[ $1 =~ ([[:digit:]])(-([[:digit:]]))?   ]]; then
    from=${BASH_REMATCH[1]}
    to=${BASH_REMATCH[3]}
  else
    echo bad range
  fi;shift
  array=( ${@} )
  local start=${array[@]::${from}}
  local rest
  [ -n "$to" ] && rest=${array[@]:((${to}+1))}  || rest=${array[@]:((${from}+1))}
  echo ${start[@]} ${rest[@]}
}

q=( `remove 1 ${q[*]}` )
echo ${q[@]}
~                                                                                                                                                              
~                       

4
นี่จะดีกว่านี้ถ้ามีบางสิ่งที่จะอธิบายวิธีการทำงานและไม่เพียงแค่หยดโค้ด แล้วตัวหนอนที่ด้านล่างล่ะ?
CVN

3
อย่างจริงจังคุณถูกต้อง ดูเหมือนว่ามันจะถูกเขียนโดยนักเลงหัวไม้ แต่ขอบคุณ ฉันแค่แอบเข้าไปในระหว่างวันที่ให้บริการแฮมเบอร์เกอร์
MageProspero

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