Những ký tự nào được yêu cầu để thoát trong các đối số dòng lệnh?


14

Trong Bash, khi chỉ định các đối số dòng lệnh cho một lệnh, những ký tự nào được yêu cầu để thoát?

Họ đang giới hạn ở những metacharacters của Bash: không gian, tab, |, &, ;, (, ), <, và >?


Đừng quên (có thể) tên tập tin toàn cầu với * và?
Jeff Schaller

Cảm ơn. Bạn có thể liệt kê đầy đủ các loại ký tự cần thoát trong cmd line args không?
Tim

Danh sách này là tốt để có, nhưng điều quan trọng nhất để hiểu về trích dẫn, là: Tất cả mọi thứ giữa các trích dẫn được truyền theo nghĩa đen và không có từ tách. Không có ngoại lệ. (Điều này có nghĩa là không có cách nào để nhúng một trích dẫn trong một trích dẫn, nhân tiện, nhưng nó rất dễ để làm việc xung quanh .)
Wildcard

Câu trả lời:


22

Các ký tự sau có ý nghĩa đặc biệt đối với chính vỏ trong một số ngữ cảnh và có thể cần phải thoát trong các đối số:

Một số trong những nhân vật đó được sử dụng cho nhiều thứ hơn và ở nhiều nơi hơn so với cái tôi liên kết.


Có một vài trường hợp góc được tùy chọn rõ ràng:

  • !có thể bị vô hiệu hóa với set +H, đó là mặc định trong shell không tương tác.
  • {có thể bị vô hiệu hóa với set +B.
  • *?có thể bị vô hiệu hóa với set -fhoặcset -o noglob .
  • =Dấu bằng (U + 003D) cũng cần được thoát nếu set -khoặcset -o keyword được bật.

Thoát một dòng mới yêu cầu trích dẫn - dấu gạch chéo ngược sẽ không thực hiện công việc. Bất kỳ nhân vật nào khác được liệt kê trong IFS sẽ cần xử lý tương tự. Bạn không cần phải thoát khỏi ]hay }, nhưng bạn làm cần phải thoát khỏi )bởi vì nó là một nhà điều hành.

Một số trong những nhân vật này có giới hạn chặt chẽ hơn khi họ thực sự cần trốn thoát hơn những người khác. Ví dụ, a#blà ok, nhưng a #blà một nhận xét, trong khi >sẽ cần thoát trong cả hai bối cảnh. Dù sao đi nữa, việc thoát khỏi tất cả chúng một cách bảo thủ, và việc ghi nhớ những nét riêng biệt sẽ không dễ dàng gì.

Nếu tên lệnh của bạn tự nó là một từ khóa shell ( if, for, do) sau đó bạn sẽ cần phải thoát khỏi hoặc trích dẫn nó quá. Điều thú vị duy nhất trong số đó là inbởi vì nó không rõ ràng rằng nó luôn là một từ khóa. Bạn không cần phải làm điều đó cho các từ khóa được sử dụng trong các đối số, chỉ khi bạn (dại dột!) Đặt tên một lệnh theo một trong số chúng. Toán tử Shell ( (, &v.v.) luôn cần trích dẫn mọi lúc mọi nơi.


1 Stéphane đã lưu ý rằng bất kỳ ký tự trống một byte nào khác từ miền địa phương của bạn cũng cần thoát. Trong hầu hết các địa phương phổ biến, hợp lý, ít nhất là các địa điểm dựa trên C hoặc UTF-8, đó chỉ là các ký tự khoảng trắng ở trên. Trong một số địa điểm ISO-8859-1, không gian không ngắt U + 00A0 được coi là trống, bao gồm Solaris, BSD và OS X (tôi nghĩ không chính xác). Nếu bạn đang làm việc với một địa điểm không xác định tùy ý, nó có thể bao gồm bất cứ thứ gì, kể cả thư, thật may mắn.

Có thể hiểu được, một byte đơn được coi là trống có thể xuất hiện trong một ký tự nhiều byte không trống và bạn không có cách nào để thoát khỏi điều đó ngoài việc đặt toàn bộ nội dung trong dấu ngoặc kép. Đây không phải là mối quan tâm về mặt lý thuyết: trong miền địa phương ISO-8859-1 từ phía trên, A0byte được coi là khoảng trống có thể xuất hiện trong các ký tự đa bào như UTF-8 được mã hóa "à" ( C3 A0). Để xử lý các ký tự đó một cách an toàn, bạn sẽ cần trích dẫn chúng "à". Hành vi này phụ thuộc vào cấu hình ngôn ngữ trong môi trường chạy tập lệnh chứ không phải nơi bạn viết nó.

Tôi nghĩ rằng hành vi này bị phá vỡ theo nhiều cách, nhưng chúng ta phải chơi theo cách chúng ta xử lý. Nếu bạn đang làm việc với bất kỳ bộ ký tự đa nhân không tự đồng bộ hóa nào, điều an toàn nhất sẽ là trích dẫn mọi thứ. Nếu bạn đang ở UTF-8 hoặc C, bạn sẽ an toàn (hiện tại).


Các khoảng trống khác trong miền địa phương của bạn cũng cần thoát ( ngoại trừ hiện tại là nhiều byte vì lỗi )
Stéphane Chazelas

Bạn chỉ cần thoát !khi mở rộng lịch sử csh, thường không có trong tập lệnh. [ ! -f a ]hoặc find . ! -name...là tốt Điều đó được bao phủ bởi phần giới hạn chặt chẽ hơn của bạn nhưng có thể đáng được đề cập rõ ràng.
Stéphane Chazelas

Lưu ý rằng có những tình huống mà nhân vật khác không cần trích dẫn như: hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], các nhà khai thác regexp cho [[ x =~ ".+[" ]]. Từ khóa khác hơn {( if, while, for...) sẽ cần phải được trích dẫn vì vậy họ đang không được công nhận như vậy ...
Stéphane Chazelas

Trong phạm vi đó là những đối số dòng lệnh, việc giải thích tùy thuộc vào lệnh đang được đề cập (giống như ]), vì vậy tôi không liệt kê chúng. Tôi không nghĩ rằng bất kỳ từ khóa cần trích dẫn ở vị trí đối số.
Michael Homer

2
Trích dẫn nội dung, dấu gạch ngang hoặc% không làm gì cả.
Michael Homer

3

Trong GNU Parallel, điều này được kiểm tra và sử dụng rộng rãi:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

Nó được thử nghiệm trên bash, dash, ash, ksh, zsh, và fish. Một số ký tự không cần trích dẫn trong một số (phiên bản) của vỏ, nhưng các ký tự trên hoạt động trong tất cả các vỏ được thử nghiệm.

Nếu bạn chỉ đơn giản muốn một chuỗi trích dẫn, bạn có thể chuyển nó thành parallel --shellquote:

printf "&*\t*!" | parallel --shellquote

Làm thế nào tôi không nghe thấy song song trước đây ...
Tom H

@TomH Sẽ được đánh giá cao nếu bạn có thể dành 5 phút để nghĩ về cách chúng tôi có thể tiếp cận bạn.
Ole Tange

Tôi nghĩ đó là một vấn đề tiến triển. hầu hết mọi người không cần hoặc hiểu song song cho đến khi họ đã vượt qua một số giai đoạn phức tạp. Đến lúc đó họ đã bắt gặp xargs, nohup và những thứ tương tự. Ngoài ra, tôi không thấy nhiều người sử dụng song song để giải quyết các vấn đề trong trao đổi ngăn xếp hoặc khi tôi tìm kiếm giải pháp cho các vấn đề bash
Tom H

1

Đối với giải pháp thoát nhẹ trong Perl, tôi tuân theo nguyên tắc trích dẫn đơn. Một chuỗi Bash trong các trích dẫn đơn có thể có bất kỳ ký tự nào, ngoại trừ chính trích dẫn đó.

Mã của tôi:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

Ví dụ chạy 1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

Ví dụ chạy 2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

Ví dụ chạy 3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

Ví dụ chạy 4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

Ví dụ chạy 5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

Có, điểm hợp lệ đó. Quan điểm của tôi là hầu hết mọi người sẽ hạ cánh trên trang này, bởi vì họ có một vấn đề cần giải quyết. Không phải vì điều này làm cho một cuộc tranh luận học thuật thú vị. Đó là lý do tại sao tôi muốn đưa ra giải pháp và thảo luận về giá trị của chúng, ngay cả khi hơi lạc đề.
Jari Turkia

Mã của tôi chỉ là một triển khai câu trả lời của Michael Homer. Tôi không có ý định mang thêm thông tin, hơn những gì anh ta đã làm.
Jari Turkia
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.