ฉันจะใช้ตัวแปร $ ในการขยายเชลล์ของลำดับได้อย่างไร


33

ฉันต้องการที่จะใช้$var inการขยายตัวของเปลือกหอยกับช่วงในทุบตี แค่วาง{$var1..$var2}ไม่ได้ดังนั้นฉันจึงไป "ด้านข้าง" ...

ผลงานต่อไปนี้ แต่มันเป็น kludge เล็กน้อย

# remove the split files
echo rm foo.{$ext0..$extN} rm-segments > rm-segments
source rm-segments

มีวิธี "ปกติ" มากกว่านี้ไหม?

คำตอบ:


26

คุณอาจต้องการลอง:

eval rm foo.{$ext0..$extN}

ไม่แน่ใจว่านี่เป็นคำตอบที่ดีที่สุดหรือไม่ แต่เป็นคำตอบเดียว


Durrh! :( ฉันไม่เห็นชัดเจน ... ขอบคุณ :)
Peter.O

4
ใน bash การขยายตัว {} เกิดขึ้นก่อนการขยาย $ ดังนั้นฉันไม่คิดว่าจะมีวิธีอื่นนอกเหนือจากการใช้ eval หรือเคล็ดลับอื่น ๆ ที่ทำให้เกิดการส่งผ่านสองครั้งผ่านนิพจน์
mattdm

6
ฉันแค่ "ได้รับ" มัน! ... ไม่มีการขยายรั้งด้วย{$one..$three}เพราะมันไม่ใช่รูปแบบที่ถูกต้องของการขยายรั้งซึ่งในกรณีนี้คาดว่าจำนวนเต็ม ... มันจะกลายเป็นรูปแบบที่ถูกต้องหลังจากการขยาย $ var ซึ่งevalจากนั้นจะผ่านกระบวนการเดียวกันเพื่อสร้างการขยายลำดับการจัดฟันปกติ ... 1 2 3 QED;) ... สรุป: การปรากฏตัวที่เรียบง่ายของคู่รั้งไม่ก่อให้เกิดการขยายรั้ง ... เฉพาะรูปแบบที่ถูกต้องทริกเกอร์มัน .
Peter.O

@fred: ยินดีต้อนรับ :-)
asoundmove

เมื่อใช้ตัวแปรเหมือนa={0..9}; echo $a;ไม่มีนามสกุลรั้ง ใช้evalมันได้ผล ดังนั้นฉันคิดว่าคำอธิบายของ @ mattdm นั้นดี
dr0i

20

ในขณะที่คุณตระหนักแล้ว{1..3}ขยายไป1 2 3แต่{foo..bar}หรือ{$foo..$bar}ไม่ขยายตัวรั้งทริกเกอร์และหลังมีการขยายต่อมาแทนที่$fooและ$barโดยค่าของพวกเขา

fallback บน GNU (เช่น Linux ที่ไม่ใช่แบบฝัง) คือseqคำสั่ง

for x in `seq $ext0 $extN`; do rm foo.$x; done

ความเป็นไปได้อีกอย่างหนึ่ง หากfoo.ไม่มีอักขระพิเศษของเชลล์คือ

rm `seq $ext0 $extN | sed 's/^/foo./'`

ทางออกที่ง่ายที่สุดคือการใช้ zsh ในrm foo.{$ext0..$extN}สิ่งที่คุณต้องการ


ขอบคุณสำหรับตัวเลือก .. มันเป็นเรื่องดีที่ได้เห็นพวกเขาทั้งหมดจัดเป็นกลุ่ม .. ฉันจะติดกับ bash และ eval ... eval นั้นง่ายพอตอนนี้ที่ฉันรู้ว่าเกิดอะไรขึ้นเบื้องหลัง; ดังนั้นจึงไม่มีปัญหาอีกต่อไป ไม่จำเป็นต้องเปลี่ยนม้าดีๆเพราะผู้ขับขี่
:)

1

ในขณะที่คำตอบอื่น ๆ พูดถึงการใช้evalและseqในbashคุณสามารถใช้การforวนซ้ำสไตล์ C แบบดั้งเดิมในบริบททางคณิตศาสตร์ ตัวแปรext0และextNถูกขยายภายใน((..))ทำให้ลูปทำงานในช่วงที่กำหนด

for (( idx = ext0; idx <= extN; idx++ )); do
    [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
    rm "$foo.$idx"
done

หากคุณกำลังมองหาวิธีที่ดีที่สุดและหลีกเลี่ยงrmคำสั่งหลาย ๆคำสั่งคุณสามารถใช้ตัวยึดตำแหน่งชั่วคราวเพื่อจัดเก็บผลลัพธ์ชื่อไฟล์และการโทรแบบrmครั้งเดียว

 results=()
 for (( idx = ext0; idx <= extN; idx++ )); do
     [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
     results+=( "$foo.$idx" )
 done

และตอนนี้เรียกrmคำสั่งในอาร์เรย์ที่ขยาย

 rm -- "${results[@]}"

0
    function f_over_range {
        for i in $(eval echo {$1..$2}); do
            f $i
        done
    }

    function f {
        echo $1
    }

    f_over_range 0 5
    f_over_range 00 05

หมายเหตุ:

  • การใช้ eval exposes ความเสี่ยงด้านความปลอดภัยในการฉีดคำสั่ง
  • Linux จะพิมพ์ "00 \ n01 \ n02..etc" แต่ OSX จะพิมพ์ "1 \ n2 \ n ... etc"
  • การใช้ seq หรือ C-style สำหรับลูปจะไม่ตรงกับการจัดการค่าศูนย์นำหน้า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.