rsync: loại trừ không hoạt động khi sử dụng biến


0

Ai đó có thể vui lòng giải thích cho tôi hành vi này tôi đã nhận thấy gần đây khi tôi đang đồng bộ hóa một thư mục với một máy chủ khác thông qua rsync không? Tôi muốn loại trừ thư mục con "xong" trong trường hợp này.

Khi tôi đặt các tùy chọn để sử dụng với rsync vào một biến, thư mục đó không bị loại trừ. Nhưng đó là khi tôi đặt các tùy chọn trực tiếp đằng sau cuộc gọi rsync. Các thay đổi đối với "-av" đã tạo ra sự khác biệt, nhưng loại trừ không hoạt động.

rsync 3.0.9-18, trên bash, CentOS 7.4

Không bị loại trừ:

$ RSYNC_OPTIONS='-av --exclude "done"'
$ touch done/test.ignore && rsync ${RSYNC_OPTIONS} ${SOURCEDIR} ${TARGET}
sending incremental file list
done/test.ignore

sent 132 bytes  received 32 bytes  109.33 bytes/sec
total size is 0  speedup is 0.00

Không bao gồm:

$ touch done/test.ignore && rsync -av --exclude "done" ${SOURCEDIR} ${TARGET}
sending incremental file list

sent 41 bytes  received 12 bytes  106.00 bytes/sec
total size is 0  speedup is 0.00

Câu trả lời:


2

Tôi đã nhân rộng vấn đề và sử dụng set -x để xem cả hai lệnh thực sự trông như thế nào. Hóa ra lệnh này

rsync ${RSYNC_OPTIONS} ${SOURCEDIR} ${TARGET}

thực tế là tương đương với điều này

rsync -av --exclude '"done"' ${SOURCEDIR} ${TARGET}

Lưu ý các trích dẫn trong dấu ngoặc kép. Mẫu của bạn không done; nó là "done", như thể thư mục bạn muốn loại trừ có dấu ngoặc kép trong tên thật của nó.


Để khắc phục điều này, bạn có thể khai báo biến mà không cần các trích dẫn rắc rối này:

RSYNC_OPTIONS='-av --exclude done'                           # poor fix, don't
rsync ${RSYNC_OPTIONS} "${SOURCEDIR}" "${TARGET}"

Nhưng điều này sẽ phản tác dụng nếu mô hình chứa khoảng trắng, vv Một cách tiếp cận khác có thể là với eval:

RSYNC_OPTIONS='-av --exclude "name  with  double  spaces"'
eval rsync "${RSYNC_OPTIONS}" '"${SOURCEDIR}" "${TARGET}"'   # not recommended

eval sẽ phân tích cú pháp lần thứ hai. Thật khó để sử dụng nó đúng cách và an toàn. Tôi trích dẫn đôi ${RSYNC_OPTIONS} vì thế "name with double spaces" không mất không gian gấp đôi. Tôi độc thân trích dẫn "${SOURCEDIR}" "${TARGET}", vì vậy các biến này không được mở rộng ngay lập tức (nếu không nội dung của chúng sẽ trải qua quá trình mở rộng). Đây là khó khăn!

Bên cạnh đó, những gì về name "with' quotes? Để lấy chuỗi chính xác này làm đối số tùy chọn cho rsync --exclude bạn cần một số trích dẫn mơ hồ và thoát ra trong RSYNC_OPTIONS tờ khai. Có nhiều lý do để tránh eval.


Giải pháp thực sự là sử dụng một mảng trong Bash. Mảng lưu ý là không di động.

RSYNC_OPTIONS=(-av --exclude 'name with  spaces and $u(h')
rsync "${RSYNC_OPTIONS[@]}" "${SOURCEDIR}" "${TARGET}"

Tôi hiểu lý do tại sao bạn không trích dẫn ${RSYNC_OPTIONS} trong cách tiếp cận ban đầu của bạn. Bạn nên trích dẫn ${SOURCEDIR} và (riêng biệt) ${TARGET} Tuy nhiên. Lệnh trên trích dẫn từng biến đúng.

Hoặc có thể ${SOURCEDIR} có nghĩa là để xác định nhiều nguồn? Đây sẽ là lý do để không trích dẫn nó, nhưng sau đó nó có thể mang lại những vấn đề tương tự như ${RSYNC_OPTIONS}. Trong trường hợp này, bạn chắc chắn nên sử dụng một biến mảng ở đây là tốt.

Cũng xem xét tên biến trong chữ thường .


Cảm ơn rất nhiều cho lời giải thích kỹ lưỡng này! Không đặt các biến khác trong dấu ngoặc kép vì chúng thực sự là hằng số (tôi biết chính xác một giá trị mà chúng chứa). Sẽ có một cái nhìn vào liên kết "chữ thường".
Larsen

-1

Điều gì về việc đặt dấu ngoặc kép của bạn như thế này?

RSYNC_OPTIONS='-av --exclude '"done"''

Tôi chỉ thử nghiệm nó trên một lệnh đơn giản hóa:

SEP='-F ";"'
echo "1;2;3" | awk ${SEP} '{print $2}'

(không làm việc)

SEP='-F '";"''
echo "1;2;3" | awk ${SEP} '{print $2}'

(đang làm việc)


Chỉnh sửa:

Với kỹ thuật @Kamil, mảng cũng hoạt động tốt:

SEP=(-F ";")
echo "1;2;3" | awk ${SEP[@]} '{print $2}'

2
Một cá trích đỏ. SEP='-F '";"'' định nghĩa cùng một giá trị biến SEP='-F ;' (so sánh declare -p SEP trong cả hai trường hợp), do đó, ví dụ làm việc của bạn chỉ là "sửa chữa kém" của tôi ngụy trang. Tôi đánh giá thấp vì câu trả lời này không mang lại điều gì mới, ngoại trừ kỹ thuật trích dẫn kỳ lạ này mà chỉ làm phiền vấn đề.
Kamil Maciorowski

@KamilMaciorowski Tôi là một người mới chơi bash, tôi chỉ muốn nghĩ rằng có một cách giải quyết với việc chỉ sử dụng chuỗi, nhưng rõ ràng là tôi đã sai.
Yoric

Vâng, trong thực tế có một cách giải quyết. Nó liên quan đến eval và nó khá khủng khiếp. Câu trả lời của tôi hiện đang được cập nhật để bao gồm điều này. Mặc dù tôi nghĩ rằng câu trả lời của bạn ở đây không hữu ích, nhưng có hai câu trả lời khác của bạn mà tôi nêu lên hôm nay. Theo tôi có một rủi ro ở đây, nhưng nói chung bạn đang làm tốt.
Kamil Maciorowski

@KamilMaciorowski Cảm ơn bạn đã thêm vào lời giải thích đã rõ ràng và mối quan tâm của bạn. Chúng tôi học được rất nhiều từ các kỹ thuật viên có kinh nghiệm như bạn đủ tử tế để dành thời gian thậm chí đặt các liên kết thích hợp để đọc thêm. Tôi ổn khi sai miễn là tôi tìm hiểu thêm :) Tôi chỉ ngạc nhiên với Thế giới Linux và một chút thất vọng khi không biết 5% về nó.
Yoric
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.