Nối chuỗi Bash được sử dụng để xây dựng danh sách tham số


12

Cho mảnh bash này:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

Tiếng vang hiển thị chuỗi PARMS như mong đợi, không có lỗi nào được hiển thị, nhưng rsync âm thầm hoạt động như thể các tùy chọn được thêm bởi + = không tồn tại. Tuy nhiên, điều này hoạt động như mong đợi:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

Tôi đoán rằng tôi đã làm hỏng cái gì đó với dấu ngoặc kép (luôn có vấn đề với những cái đó), nhưng không chắc chắn chính xác những gì và tại sao các tùy chọn bị bỏ qua mặc dù chuỗi dường như đã được xây dựng chính xác.


1
echo "$PARMS"rsync "${PARMS}"...
jasonwryan

Điều này làm việc với tôi với bashphiên bản 4.2.25 mà không có bất kỳ thay đổi nào.
Anthon

Câu trả lời:


17

Có một sự khác biệt giữa:

PARMS+="... --exclude='.git'"

... --exclude='.git'

Đầu tiên, các trích dẫn đơn nằm trong chính các trích dẫn, vì vậy chúng có mặt theo nghĩa đen trong văn bản thay thế được đưa ra rsynclàm đối số. rsyncnhận được một đối số có giá trị là --exclude='.git'. Trong lần thứ hai, các trích dẫn duy nhất được giải thích bởi trình bao tại thời điểm chúng được viết, bởi vì chúng không nằm trong chính các trích dẫn và rsyncđược xem --exclude=.git.

Trong trường hợp này, bạn hoàn toàn không cần một dấu ngoặc đơn - .gitlà một từ vỏ hoàn toàn hợp lệ, không có ký tự đặc biệt, vì vậy bạn có thể sử dụng nó theo nghĩa đen trong lệnh.

Mặc dù vậy, tốt hơn cho loại điều này là một mảng :

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

Điều này xây dựng lệnh của bạn dưới dạng các từ riêng biệt, với bất kỳ trích dẫn nào bạn muốn diễn giải tại thời điểm bạn viết dòng mảng. "${PARMS[@]}"mở rộng đến từng mục trong mảng dưới dạng một đối số riêng biệt, ngay cả khi chính đối số đó có các ký tự hoặc khoảng trắng đặc biệt trong đó, vì vậy hãy rsyncxem những gì bạn đã viết như bạn muốn nói.


bashthực hiện tách từ sau khi ${PARMS}được mở rộng. Vì vậy, trích dẫn duy nhất cũng được giải thích bởi vỏ.
cuonglm

2
Thử nó! Tôi đã làm. Các trích dẫn vẫn còn, và nếu có khoảng trắng ở giữa chúng là các điểm phân chia.
Michael Homer

@Gnouc: Từ trang bash người đàn ông: "Trích dẫn diệt: Sau khi mở rộng trước đó, tất cả các lần xuất hiện không thể viện chứng của các nhân vật \ , '". Điều đó không là kết quả của một trong những bản mở rộng trên được gỡ bỏ" "Mở rộng trên" bao gồm Mở rộng tham số thực hiện việc mở rộng ${PARMS}.
camh

Cảm ơn. Vì vậy, tôi hiểu rằng trong trường hợp đó, bỏ qua các dấu ngoặc đơn bên trong dấu ngoặc kép sẽ hoạt động nhưng vì sự hoàn chỉnh - vì nếu tôi cần trích dẫn một số ký tự đặc biệt và không muốn sử dụng phương pháp sau của bạn thì sao?
neuviemeporte

Nếu các ký tự đặc biệt của bạn không phải là một phần của IFS(nói chung, khoảng trắng), bạn không cần trích dẫn chúng. Nếu đúng như vậy, bạn sẽ không gặp may trừ khi bạn hack thứ gì đó cùng với eval- đây là một chút sai lầm nói chung và mảng là cách đúng đắn để đối phó với nó.
Michael Homer

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.