Bash: dòng lệnh với các đối số tùy chọn


7

Tôi đang chạy loại mã này:

#!/usr/bin/env bash
set -u
exclude1='--exclude=/path/*'
exclude2='--exclude=/path with spaces/*'
exclude3=''        # any 'exclude' can be empty
tar -czf backup.tgz "$exclude1" "$exclude2" "$exclude3" 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Khi tôi chạy mã này, tôi gặp lỗi này:

tar: : Cannot stat: No such file or directory

Điều này là do "$ Elim3" được dịch là một đối số trống. Chính xác như thể tôi đã làm điều này:

tar -czf backup.tgz "$exclude1" "$exclude2" ''

Một cách để tránh lỗi này là xóa dấu ngoặc kép quanh $ ElimX. Nhưng đây là một vấn đề nếu $ ElimX chứa bất kỳ khoảng trắng hoặc các ký tự lạ khác.

Một cách khác là sử dụng evalnhưng vì tôi cần giữ dấu ngoặc kép, tôi không thấy cách loại bỏ dấu ngoặc kép VÀ các đối số trống khi cần.

Giải pháp duy nhất tôi tìm thấy là xây dựng dòng lệnh với nối chuỗi:

CMD='tar -czf backup.tgz'
if [[ -n "$exclude1" ]]; then CMD+=" \"$exclude1\" "; fi
if [[ -n "$exclude2" ]]; then CMD+=" \"$exclude2\" "; fi
if [[ -n "$exclude3" ]]; then CMD+=" \"$exclude3\" "; fi
eval $CMD 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Bất cứ ai có một ý tưởng thông minh hơn?

Câu trả lời:


7
tar -czf backup.tgz "$exclude1" "$exclude2" ${exclude3+"$exclude3"} 2>&1

${exclude3+"$exclude3"}mở rộng thành không có gì, nếu $exclude3không được đặt và "$exclude3"nếu được đặt.

(và tương tự cho các biến khác có khả năng chưa được đặt.)

Lưu ý rằng có một sự khác biệt giữa một biến unset và một biến được đặt thành chuỗi trống, vì vậy bạn nên sử dụng

unset exclude3

thay vì

exclude3=''

1
Thủ thuật hay, nhưng nếu $ Elim3 không được đặt thì Bash sẽ báo lỗi vì 'set -u' được sử dụng như một biện pháp an toàn.
Gregory MOUSSAT

Nó hoạt động miễn là bạn chỉ kiểm tra xem biến có được đặt hay không. Kiểm tra không được tính là cố gắng thực hiện mở rộng tham số trên biến .
Uwe

1
Nhân tiện, có một cấu trúc liên quan xử lý các biến không đặt và biến rỗng theo cùng một cách, cụ thể là ${exclude3:+"$exclude3"}(lưu ý dấu hai chấm).
Uwe

7

Vì bạn đang làm việc trong bash, hãy sử dụng một mảng .

excludes=()
excludes+=('--exclude=/path/*')

tar -czf backup.tgz "${excludes[@]}"

Nếu bạn có một mục tùy chọn trong một số biến, hãy thêm nó vào một điều kiện.

if [[ -n $exclude_or_empty ]]; then excludes+=("$exclude_or_empty"); fi

1

Điều này hoạt động với tôi trong bash trên Ubuntu, nhưng tôi không có manh mối nào, cho dù đó là tuân thủ / tương thích POSIX:

tar -czf backup.tgz \
$(if "$exclude1" != ""); then echo "$exclude1"; fi
$(if "$exclude2" != ""); then echo "$exclude3"; fi
$(if "$exclude3" != ""); then echo "$exclude3"; fi
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.