Tại sao các trích dẫn cần thiết cho đối số tệp khi gọi tập lệnh Bash này?


13

Tôi còn khá mới với kịch bản Bash. Tôi có một "bản kiểm tra", mà tôi đã sử dụng làm cơ sở cho một tập lệnh nâng cao / hữu ích hơn:

#!/bin/bash
files=$1
for a in $files
do
    echo "$a"
done

Khi tôi gọi nó mà không có bất kỳ trích dẫn nào, nó chỉ chọn một tập tin trong một thư mục:

testscript *.txt

Nhưng khi tôi gọi nó bằng dấu ngoặc kép, nó hoạt động chính xác và chọn ra tất cả các tệp văn bản:

testscript '*.txt'

Chuyện gì đang xảy ra ở đây?


Để trở thành rất, rất rõ ràng, đúng cách để sửa lỗi này là chạy for a in "$@"; do(hoặc for a; do) trong kịch bản của bạn, do đó rời khỏi globbing với lớp vỏ bên ngoài, chứ không phải để bỏ qua các dấu ngoặc kép.
Charles Duffy


Điều này cũng đáng xem. hướng dẫn.bash.academy
vascowhite

Câu trả lời:


29

Khi bạn gọi một chương trình

testscript *.txt

sau đó shell của bạn thực hiện việc mở rộng và thực hiện tất cả các giá trị. Vì vậy, nó có thể, có hiệu quả gọi chương trình của bạn là

testscript file1.txt file2.txt file3.txt file4.txt

Bây giờ chương trình của bạn chỉ nhìn vào $1và vì vậy chỉ hoạt động trên file1.txt.

Bằng cách trích dẫn trên dòng lệnh, bạn đang truyền chuỗi ký tự *.txtcho tập lệnh và đó là những gì được lưu trữ trong $1. forVòng lặp của bạn sau đó mở rộng nó.

Thông thường bạn sẽ sử dụng "$@"và không có $1trong các kịch bản như thế này.

Đây là một "Gotcha" cho những người đến từ CMD kịch bản, nơi vỏ lệnh không làm globbing (vì nó được biết đến) và luôn luôn vượt qua chuỗi chữ.


6
Chỉ cần làm rõ (đối với những người không phải là tác giả của câu trả lời ở trên), việc sử dụng "$@"(trái ngược với $@hoặc $1 $2 $3) sẽ khiến mỗi tên tệp được trích dẫn, "file1.txt" "file2.txt"v.v ... Đối với file1.txtđiều này là vô nghĩa, nhưng nếu bạn có my file.txt, trích dẫn là rất quan trọng để ngăn chặn trình bao phân tích cú pháp để biến nó thành hai tên tệp, một tên myvà một tên file.txt. Luôn luôn trích dẫn đầu vào của người dùng và mở rộng toàn cầu kẻo bạn sẽ rất không vui một ngày nào đó.
Seth Robertson

2
Và đây không chỉ là lý thuyết - Mac OS X đã từng được phát hành với một kịch bản cập nhật không trích dẫn chính xác các đối số và cuối cùng đã xóa ổ cứng của mọi người trong một số trường hợp.
lông mịn

2
@fluffy, bạn có liên kết về điều đó không?
tự đại diện

@Wildcard Thật không may, tôi không thể tìm thấy bất kỳ bài viết nào về nó, nhưng đó là tin tức lớn trong thế giới công nghệ khi nó xảy ra. Tôi muốn nói rằng đó là vào năm 2003/2004 hoặc sau đó, khi Apple vẫn còn là một nhà phân phối UNIX.
lông mịn

1
@wildcard À, tìm được rồi! xlr8yourmac.com/OSX/itunes2_erased_drive.html - đó thực sự là một kịch bản nâng cấp iTunes là thủ phạm.
lông mịn

7

Không có dấu ngoặc kép, shell sẽ mở rộng *.txttrước khi gọi script, vì vậy $1đây chỉ là tệp đầu tiên được mở rộng. Tất cả các txttệp là đối số cho tập lệnh của bạn tại thời điểm đó (giả sử không có quá nhiều).

Với dấu ngoặc kép, chuỗi được truyền mà không được mở rộng thành tập lệnh, sau đó cho phép formở rộng, như bạn đang hy vọ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.