Shell Script: tạo một biến với các tùy chọn bên trong


11

Tôi có một lệnh rsync với các tham số sau:

rsync -avz --{partial,stats,delete,exclude=".*"}

Tôi muốn đặt các tham số đó bên trong một biến để sử dụng lại nó sau trong tập lệnh. Một cái gì đó như thế này:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

Tôi đã thử với dấu ngoặc kép, dấu ngoặc đơn, dấu ngoặc, nhưng không thành công.


Câu hỏi tương tự trên SO: stackoverflow.com/questions/13365553/ từ
Barmar

Đã từng xuống tuyến đường này trước đó: Hãy chắc chắn rằng chuỗi lệnh kết quả cuối cùng của bạn không có bất kỳ chuỗi trống nào trong đó. Nếu đúng như vậy, rsync có thể sử dụng chúng làm tham số và vì chúng vô hình, nên rất khó để gỡ lỗi. Tôi đã có một tham số đầu tiên trống và rsync diễn giải nó như bao gồm thư mục hiện tại trong các nguồn của những thứ cần sao chép.
Joe

Câu trả lời:


12

Đặt một lệnh phức tạp trong một biến không phải là một cách tiếp cận được khuyến nghị. Xem BashFAQ / 050 - Tôi đang cố gắng đặt một lệnh vào một biến, nhưng các trường hợp phức tạp luôn thất bại!

Yêu cầu của bạn trở nên thực sự đơn giản, nếu bạn chỉ quyết định sử dụng hàm thay vì biến và truyền đối số cho nó.

Cái gì đó như

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

và bây giờ chuyển các đối số cần thiết cho nó như là

rsync_custom /dir1 /dir2

Định nghĩa hàm khá đơn giản, trước tiên chúng ta kiểm tra số lượng đối số đầu vào bằng cách sử dụng biến $#không nên bằng không. Chúng tôi ném một thông báo lỗi nói rằng không có đối số được cung cấp. Nếu có các đối số hợp lệ, thì "$@"đại diện cho các đối số thực tế được cung cấp cho hàm.

Nếu đây là một chức năng bạn sẽ sử dụng khá thường xuyên, ví dụ như trong tập lệnh / dòng lệnh, hãy thêm nó vào tập tin khởi động shell .bashrc, .bash_profilechẳng hạn.

Hoặc như đã lưu ý, có thể đáng để mở rộng việc mở rộng niềng răng để tách các đối số để dễ đọc hơn vì

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}

5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Điều này cố gắng chạy lệnh -avzvới các đối số --partial, --statsvv .. và VARđược thiết lập rsynctrong môi trường.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

Biểu mẫu được trích dẫn không hoạt động vì dấu ngoặc nhọn không được mở rộng trong dấu ngoặc kép và không nằm trong các xác nhận và chúng không được mở rộng sau khi một biến được mở rộng.

Nếu bạn cần lưu trữ các đối số dòng lệnh trong một biến, hãy sử dụng một mảng:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Bây giờ "${args[@]}"sẽ mở rộng sang rsync, -avz, --partial, vv như lời riêng biệt.

Mảng cũng cho phép bạn nối các tùy chọn vào danh sách, tùy theo điều kiện nếu cần, vì vậy bạn có thể:

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"

1

Bạn ít nhất có thể lưu các tùy chọn một phần trong một biến:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

Kiểm tra là quan trọng, bởi vì mặt nạ có thể khó khăn:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Vì có nhiều lựa chọn thay thế, như sử dụng lịch sử, sử dụng bí danh, sử dụng hàm, không có trường hợp sử dụng rõ ràng nào tôi có thể nghĩ ra. Ít khi có một tùy chọn chia sẻ phức tạp giữa các chương trình khác nhau, vì vậy đối với một giải pháp đặc biệt cho lớp vỏ tương tác, răng cưa có vẻ là một cách tốt hơn:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Mẫu của bạn

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

không thể làm việc, vì bài tập được kết thúc ở ô trống đầu tiên. Bạn phải che dấu những khoảng trống:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

một điều khá nguy hiểm để thử nghiệm, với tùy chọn - đã hết, phải không? Vì các tùy chọn có thể chứa lại "," và các trích dẫn đơn, việc che dấu có thể gặp khó khăn rất sớm. Tôi sẽ đi cho một bí danh hoặc dựa vào lịch sử.

Một bí danh có thể được lưu trữ trong tệp ~ / .bashrc để sử dụng liên tục qua nhiều phiên. Các hàm cũng có thể được lưu trữ trong bashrc, nhưng bạn chỉ cần chúng, nếu bạn muốn xử lý các tham số, được chuyển vào hàm để được đánh giá trong đó.

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.