Làm cách nào tôi có thể sử dụng biến $ trong phần mở rộng dấu ngoặc kép của chuỗi?


33

Tôi muốn sử dụng $var inmột mở rộng nẹp vỏ với một phạm vi, trong bash. Đơn giản là {$var1..$var2}không làm việc, vì vậy tôi đã đi "bên" ...

Các công việc sau đây, nhưng đó là một chút bùn.

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

Có cách nào "bình thường" hơn không?

Câu trả lời:


26

Bạn có thể muốn thử:

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

Không chắc đây có phải là câu trả lời hay nhất không, nhưng chắc chắn nó là một.


Durrh! :( Tôi không thể thấy rõ ràng ... Cảm ơn :)
Peter.O

4
Trong bash, việc mở rộng {} xảy ra trước khi mở rộng $, vì vậy tôi không nghĩ có cách nào khác để làm điều này ngoài việc sử dụng eval hoặc một số mẹo khác để khiến hai lần chuyển qua biểu thức.
mattdm

6
Tôi chỉ là "có" nó! ... Có không mở rộng cú đúp với {$one..$three}, bởi vì nó không phải là một hình thức hợp lệ cú đúp mở rộng, mà trong trường hợp này hy vọng số nguyên ... Nó chỉ trở thành một hình thức có hiệu lực sau khi mở rộng $ var, mà evalsau đó đi qua quá trình tương tự để tạo ra một bình thường mở rộng chuỗi đôi ... 1 2 3 QED;) ... Tóm tắt: đơn giản hiện diện của một cặp dấu ngoặc mở rộng does't cò cú đúp ... chỉ là một hình thức gây nên có giá trị nó .
Peter.O

@fred: Chào mừng :-)
asoundmove

Khi sử dụng một biến như a={0..9}; echo $a;không có phần mở rộng cú đúp . Sử dụng eval, nó hoạt động. Vì vậy, tôi nghĩ rằng lời giải thích của @ mattdm là tốt.
dr0i

20

Như bạn đã nhận ra, {1..3}mở rộng đến 1 2 3nhưng {foo..bar}hoặc {$foo..$bar}không kích hoạt mở rộng cú đúp và sau đó được mở rộng để thay thế $foo$barbằng các giá trị của chúng.

Một dự phòng trên GNU (ví dụ Linux không nhúng) là seqlệnh.

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

Khả năng khác. nếu foo.không chứa ký tự đặc biệt shell, là

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

Giải pháp đơn giản nhất là sử dụng zsh, nơi rm foo.{$ext0..$extN}bạn muốn.


Cảm ơn các lựa chọn .. Thật tốt khi thấy tất cả chúng được nhóm lại .. Tôi sẽ gắn bó với bash và eval ... eval đủ đơn giản để tôi biết những gì đang diễn ra sau hậu trường; vì vậy nó không còn là vấn đề nữa Không cần phải thay đổi một con ngựa tốt vì người cưỡi :) ...
Peter.O

1

Trong khi các câu trả lời khác thảo luận về việc sử dụng evalseq, trong bash, bạn có thể sử dụng forvòng lặp kiểu C truyền thống trong ngữ cảnh số học. Các biến ext0extNđược mở rộng bên trong ((..))khiến cho vòng lặp chạy cho phạm vi được xác định.

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

Nếu bạn đang tìm kiếm một cách tối ưu và tránh nhiều rmlệnh, bạn có thể sử dụng trình giữ chỗ tạm thời để lưu trữ kết quả tên tệp và gọi rmtrong một lần.

 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

và bây giờ gọi rmlệnh trên mảng mở rộng

 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

Ghi chú:

  • Sử dụng eval làm lộ rủi ro bảo mật tiêm lệnh
  • Linux sẽ in "00 \ n01 \ n02..etc", nhưng OSX sẽ in "1 \ n2 \ n ... vv"
  • Sử dụng kiểu seq hoặc kiểu C cho các vòng lặp sẽ không khớp với việc xử lý các số 0 hàng đầu của niềng răng
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.