Làm cách nào để phủ định một bài kiểm tra với các biểu thức chính quy trong tập lệnh bash?


173

Sử dụng GNU bash (phiên bản 4.0.35 (1) -release (x86_64-suse-linux-gnu), tôi muốn phủ nhận một thử nghiệm với Biểu thức chính quy. Ví dụ, tôi muốn thêm một cách có điều kiện vào biến PATH, nếu đường dẫn chưa có, như trong:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Tôi chắc chắn có một triệu cách để làm điều này, nhưng điều tôi muốn biết là liệu điều kiện có thể bị phủ nhận bằng cách nào đó, như trong (lỗi):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH

Câu trả lời:


192

Bạn đã đúng, chỉ cần đặt một khoảng trắng giữa ![[tương tựif ! [[


14
Oye vey! Ngay khi tôi an toàn vượt qua sự điên rồ của nhân vật đặc biệt giữa các thiên hà, tôi thấy mình lạc vào không gian bash (vị trí)! (Tôi cảm thấy sợ siết ruột mình như một con trăn.) Cảm ơn!
David Rogers

126

Bạn cũng có thể đặt dấu chấm than bên trong ngoặc:

if [[ ! $PATH =~ $temp ]]

nhưng bạn nên neo mô hình của bạn để giảm tích cực sai:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

tìm kiếm một trận đấu ở đầu hoặc cuối bằng dấu hai chấm trước hoặc sau nó (hoặc cả hai). Tôi khuyên bạn nên sử dụng tên biến chữ thường hoặc chữ thường trong trường hợp như một thói quen để giảm khả năng va chạm tên với biến shell.


Ah, cảm ơn đã nhắc nhở về neo. Ý tưởng sử dụng tên viết thường hoặc tên biến hỗn hợp gây nhầm lẫn cho người mới bắt đầu bash, vì lời khuyên tôi đã thấy cho đến nay là sử dụng chữ hoa. Tôi hiểu điểm bạn đang thực hiện, nhưng tôi chưa thấy đủ các ví dụ về kịch bản bash để cảm thấy thoải mái khi đi chệch khỏi (hiểu biết của tôi) về sách dạy nấu ăn.
David Rogers

4
@anyoneis tin tưởng chúng tôi về điều này. Nên tránh sử dụng các biến chữ hoa do người dùng định nghĩa. Tất cả các biến trong bash được mở rộng với $vì vậy không có lý do gì để viết hoa chúng để làm cho chúng nổi bật.
Cuộc bao vây

Tôi thấy if [[ ! $foo =~ bar ]]an toàn hơn if ! [[ $foo =~ bar ]], bởi vì nó dễ dàng giới thiệu nhiều điều kiện hơn choif
CTodea

19

cách an toàn nhất là đặt! cho phủ định regex trong [[ ]]như thế này:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

nếu không nó có thể thất bại trên các hệ thống nhất định.


9

Có, bạn có thể phủ nhận bài kiểm tra vì SiegeX đã chỉ ra.

Tuy nhiên, bạn không nên sử dụng các biểu thức thông thường cho việc này - nó có thể thất bại nếu đường dẫn của bạn chứa các ký tự đặc biệt. Hãy thử điều này thay thế:

[[ ":$PATH:" != *":$1:"* ]]

(Nguồn)


1
Một lý do khác để sử dụng biểu mẫu này là nó sẽ không vô tình khớp với các chuỗi con (ví dụ: không thêm "/ bin" vào đường dẫn vì "/ usr / bin" đã có sẵn).
Gordon Davisson

Phải mất một thời gian tôi mới hiểu làm thế nào các dấu hai chấm bên trái đã cho tôi chỗ neo mà tôi muốn. ý tưởng giảm mẫu bằng cách thêm vật liệu vào chuỗi cần tìm là đáng ghi nhớ. Tôi không hiểu tại sao các ký tự đặc biệt trong đường dẫn sẽ phá vỡ giải pháp regex nhưng không phải là giải pháp mô hình bash. Bạn có thể cho tôi một ví dụ?
David Rogers

Tôi không nghĩ rằng nó sẽ hoạt động đáng tin cậy trong mọi trường hợp. Kết hợp Regex trong IMHO vượt trội
Felipe Alvarez

5

Tôi muốn đơn giản hóa mã mà không sử dụng các toán tử có điều kiện trong các trường hợp như vậy:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
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.