bash: làm thế nào để vượt qua các đối số dòng lệnh có chứa các ký tự đặc biệt


31

Tôi đã tự viết cho mình một chương trình linux programcần một biểu thức chính quy làm đầu vào.

Tôi muốn gọi chương trình trong bashshell và truyền biểu thức chính quy đó làm đối số dòng lệnh cho chương trình (cũng có các đối số dòng lệnh khác). Một biểu thức chính quy điển hình trông giống như

[abc]\_[x|y]

Thật không may, các nhân vật [, ]|là nhân vật đặc biệt trong bash. Như vậy, gọi

program [abc]\_[x|y] anotheragument

không hoạt động. Có cách nào để vượt qua biểu thức bằng cách sử dụng một số loại ký tự thoát hoặc dấu ngoặc kép, v.v.?

(Gọi program "[abc]\_[x|y] anotheragument"cũng không hoạt động, vì nó diễn giải hai đối số là một.)

Câu trả lời:


27

Bạn có thể

  1. Thoát từng ký hiệu đặc biệt bằng dấu gạch chéo ngược (như trong \[abc\]_\[x\|y\]) hoặc
  2. Doublequote toàn bộ đối số (như trong "[abc]_[x|y]").

EDIT: Như một số người đã chỉ ra, dobleqouting không ngăn chặn sự mở rộng biến cũng như thay thế lệnh. Do đó, nếu regex của bạn chứa thứ gì đó có thể được giải thích bằng bash là một trong số đó, hãy sử dụng dấu ngoặc đơn thay thế.


4
Trong bash, trích dẫn kép không bỏ qua các biến "$HOME"hoặc tham số mở rộng "${USER:-root}", thay thế lệnh dưới dạng "$(date)"hoặc "`date`", mở rộng số học "$((1 + 2))", mở rộng lịch sử "!!"hoặc thoát dấu gạch chéo ngược "\\". Sử dụng dấu ngoặc đơn thay thế. Xem trang hướng dẫn sử dụng bash, phần có tiêu đề "Trích dẫn".
Flimm

25

Sử dụng dấu ngoặc đơn. Dấu ngoặc đơn đảm bảo rằng không có ký tự nào được diễn giải.

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

Có hai giải pháp nếu bạn cần nhúng một trích dẫn:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]

Bạn đúng. +1
antichris

6

Mỗi man bash

Có ba cơ chế trích dẫn: ký tự thoát , dấu ngoặc đơn và dấu ngoặc kép.

Dấu gạch chéo ngược không trích dẫn ( \ ) là ký tự thoát . Nó bảo tồn giá trị theo nghĩa đen của ký tự tiếp theo, ngoại trừ <newline>. Nếu một cặp \ <newline> xuất hiện và dấu gạch chéo ngược không được trích dẫn, \ <newline> được coi là tiếp tục dòng (nghĩa là, nó bị xóa khỏi luồng đầu vào và bị bỏ qua một cách hiệu quả).

Các ký tự kèm theo trong dấu ngoặc đơn duy trì giá trị theo nghĩa đen của từng ký tự trong dấu ngoặc kép. Một trích dẫn có thể không xảy ra giữa các trích dẫn đơn, ngay cả khi trước dấu gạch chéo ngược.

Việc đóng dấu các ký tự trong dấu ngoặc kép sẽ giữ giá trị bằng chữ của tất cả các ký tự trong dấu ngoặc kép, ngoại trừ $ , ` , \ , và, khi mở rộng lịch sử được bật , ! . Các ký tự $` giữ lại ý nghĩa đặc biệt của chúng trong dấu ngoặc kép. Dấu gạch chéo ngược chỉ giữ lại ý nghĩa đặc biệt của nó khi được theo sau bởi một trong các ký tự sau: $ , ` , " , \ hoặc <newline> . Một trích dẫn kép có thể được trích dẫn trong dấu ngoặc kép bằng cách đặt trước dấu gạch chéo ngược. sẽ được thực hiện trừ khi! xuất hiện trong dấu ngoặc kép được thoát bằng dấu gạch chéo ngược. Dấu gạch chéo ngược trước ! không được gỡ bỏ.

Các tham số đặc biệt *@ có ý nghĩa đặc biệt khi ở dấu ngoặc kép (xem PARAMETERS bên dưới).

Các từ có dạng $ ' chuỗi ' được xử lý đặc biệt. Từ này mở rộng thành chuỗi , với các ký tự thoát dấu gạch chéo ngược được thay thế theo quy định của tiêu chuẩn ANSI C. Các chuỗi thoát dấu gạch chéo ngược, nếu có, được giải mã như sau:

       \ a      alert (chuông)
        \ b      Backspace
        \ e 
       \ E      một ký tự thoát
        \ f      thức ăn dạng
        \ n      dòng mới
        \ r      vận chuyển trở lại
        \ t      ngang tab
        \ v      dọc tab
        \\      backslash
        \'      nháy đơn
        \"      tăng gấp đôi quote
        \ nnn    sự ký tự tám bit có giá trị là giá trị bát phân nnn
              (một đến ba chữ số)
       \ x HH    ký tự tám bit có giá trị là giá trị thập lục phân HH
              (một hoặc hai chữ số hex)
       \ u HHHH ký tự Unicode (ISO / IEC 10646) có giá trị là
              giá trị thập lục phân HHHH (một đến bốn chữ số hex)
        \ U HHHHHHHH
              ký tự Unicode (ISO / IEC 10646) có giá trị là
              giá trị thập lục phân HHHHHHHH (một đến tám chữ số hex)
        \ c x     một ký tự control- x

Kết quả mở rộng được trích dẫn một lần, như thể ký hiệu đô la không có mặt.

Một chuỗi trích dẫn kép có trước ký hiệu đô la ( $ " chuỗi " ) sẽ khiến chuỗi được dịch theo ngôn ngữ hiện tại. Nếu miền địa phương hiện tại là C hoặc POSIX , ký hiệu đô la sẽ bị bỏ qua. Nếu chuỗi được dịch và thay thế, thay thế được trích dẫn kép.


2

Bạn có thể sử dụng dấu gạch chéo ngược ( \) trước các ký tự đặc biệt để thoát chúng như vậy:

john @ awesome: ~ # echo \ &
&

2

Mặc dù nó có thể không hữu ích như một regex, một số chuỗi ký tự có thể được hiểu là tên biến Bash. Để ngăn điều này xảy ra và tránh mở rộng chúng, hãy sử dụng dấu ngoặc đơn thay vì dấu ngoặc kép:

program '[abc]_[x|y]' anotherargument

Trích dẫn từng đối số riêng biệt (nếu họ cần trích dẫn) để chúng được hiểu là đối số độc lập. Bạn cũng có thể sử dụng mảng trong một số trường hợp:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program

1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument

0

Thoát khỏi chúng nên hoạt động tốt:

  programm \[abc\]_\[x\|y\]

0

Trường hợp mô hình đến từ đâu? Là nó cố định hoặc từ một người dùng? Đó có phải là người dùng đang gọi tập lệnh trên hệ thống cục bộ hoặc ai đó ở xa không?

Bạn sử dụng dấu ngoặc kép để bọc dữ liệu để giữ cho shell không diễn giải nó. Có hai lựa chọn:

  1. Dấu ngoặc kép, vẫn cho phép một số giải thích ($ mở rộng và `backticks`)
  2. Dấu ngoặc đơn, vượt qua mọi thứ theo nghĩa đen

Bởi vì $là một ký tự hợp lệ trong regexps (dòng cuối / bộ đệm), bạn có thể muốn sử dụng dấu ngoặc đơn để giữ biểu thức chính quy, trừ khi bạn lưu trữ trong một biến. Nếu bạn đang dùng dữ liệu tùy ý từ một người không tin cậy, bạn sẽ cần phải thay thế 'với '"'"'và sau đó quấn trong đơn dấu ngoặc kép.

Lưu ý rằng có [abc]_[x|y]vẻ như bạn muốn khớp xhoặc y, trong khi nó thực sự khớp với một trong ba ký tự xy|. Dấu ngoặc vuông khớp với các ký tự trong và chỉ -cho các phạm vi và ^ở đầu bắt đầu cho phủ định. Vì vậy, [abc]_(x|y)có thể là những gì bạn muốn nói, và dấu ngoặc đơn là các ký tự đặc biệt để tạo vỏ. Dấu ngoặc vuông không đặc biệt đối với vỏ, nó trông giống như chúng. Dấu ngoặc vuông [[ ... ]]là đặc biệt.


Đây là một trong những câu trả lời đúng nhất ở đây (tôi đánh giá cao đặc biệt là hướng dẫn thay thế 'bằng '"'"'), tuy nhiên, nó vẫn không đúng. [Đây là một ký tự đặc biệt cho shell, nó được sử dụng trong các ký tự đại diện khi thực hiện mở rộng đường dẫn (shell này làm cho mọi thứ không được trích dẫn).
jpalecek

Nó đặc biệt trong một số ngữ cảnh, chẳng hạn như đăng ký biến hoặc cho toàn cầu hóa, nhưng bạn vẫn có thể nhập foo=a[b]và sau đó echo $foovà thấy rằng chuỗi không cần trích dẫn. Bạn nói đúng, tôi đã quá ngắn gọn.
Phil P

Nếu bạn không may mắn, có một tệp abtrong thư mục hiện tại, và sau đó foosẽ chứa abchứ không phải a[b]. Trích dẫn dấu ngoặc vuông của bạn, mọi người.
clacke

(Để rõ ràng: Tôi thực hiện trích dẫn (như câu trả lời ban đầu đã được làm rõ, nơi tôi đang cố gắng trích dẫn) và đây là một vấn đề phụ mà tôi đang giải quyết). Khẳng định này làm tôi ngạc nhiên, vì vậy tôi đã thử nghiệm nó. Điều đó không đúng trong zsh hoặc bash, nhưng đúng với BSD / bin / sh. Điều này chống lại POSIX và là hành vi không chuẩn, vì vậy bạn sẽ cần trích dẫn để xử lý. Trong zsh, bạn cũng có thể setopt glob_assignkích hoạt hành vi này, vì vậy trích dẫn là câu trả lời an toàn nhất.
Phil P
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.