Biểu thức chính quy trong tập lệnh bash


13

Đây là lần đầu tiên tôi bash scripting nên có lẽ tôi đang mắc một lỗi dễ dàng.

Về cơ bản, tôi đang cố gắng viết một tập lệnh có được các nhóm người dùng và nếu họ ở trong một nhóm nhất định, nó sẽ ghi nhật ký tương ứng. Rõ ràng là sẽ có nhiều chức năng hơn, nhưng không có điểm nào xây dựng mà khi tôi thậm chí không thể làm cho regex hoạt động!

Cho đến nay, tôi có điều này:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Mỗi nơi tôi đã thử regex đó, nó hoạt động. Nhưng trong tập lệnh bash, nó chỉ bao giờ xuất ra $groups, theo sau No match. Vì vậy, ai đó có thể cho tôi biết những gì sai với nó?


1
Điều gì làm cho bạn nghĩ bất cứ điều gì là sai với nó?
manatwork

1
@jrdnhannah sau đó cố gắng từ từ tạo lại regrec mục tiêu của bạn, trận đấu đầu tiên ^([a-zA-Z0-9\-_]+)sau đó thêm dấu hai chấm và cứ thế ... bạn nên tìm hiểu khá sớm, vấn đề ở đâu.
peterph

2
Tương tự ở đây với bash 4.2,45. Thoát khỏi dấu gạch dưới cố định nó. Kỳ dị. @jrdnhannah bạn có thể viết nó lên như một câu trả lời và chấp nhận nó không?
terdon

1
Vì tôi chỉ mới đăng ký Unix SE, nên tôi phải đợi 8 giờ trước khi tự trả lời. Dù vậy, rất vui khi đánh dấu nó là đã trả lời nếu có người khác làm.
jrdn

4
@terdon bash chỉ gọi các hàm regex của libc, có lẽ. Vì vậy, nó phụ thuộc vào phiên bản libc, không phải phiên bản bash. Xem câu trả lời của tôi ... (Hoặc thậm chí có thể trên chuỗi đối chiếu bạn đang sử dụng)
derobert

Câu trả lời:


14

Từ man 7 regex:

Biểu thức ngoặc là danh sách các ký tự được đặt trong "[]". Giáo dục

Để bao gồm một chữ '-', hãy biến nó thành ký tự đầu tiên hoặc cuối cùng. [A] sẽ các ký tự đặc biệt khác, bao gồm '\', mất đi ý nghĩa đặc biệt của chúng trong biểu thức ngoặc.

Việc thử regrec với egrep sẽ báo lỗi:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Đây là một phiên bản đơn giản hơn, cũng có lỗi:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

\không phải là đặc biệt, đó là một phạm vi, giống như [a-z]sẽ có. Bạn cần đặt -cuối cùng của bạn , như [_-]hoặc:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Điều này sẽ hoạt động bất kể phiên bản libc của bạn (trong cả egrep hoặc bash).

chỉnh sửa: Điều này thực sự phụ thuộc vào cài đặt ngôn ngữ của bạn quá. Trang này cảnh báo về điều này:

Phạm vi rất phụ thuộc vào trình tự đối chiếu và các chương trình di động nên tránh phụ thuộc vào chúng.

Ví dụ:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Tất nhiên, mặc dù nó không có lỗi, nhưng nó không làm những gì bạn muốn:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Đó là một phạm vi, mà trong ASCII, bao gồm \, [, ^, và _.


Hấp dẫn. My egrepkhông có lỗi, chỉ cần khớp chính xác.
manatwork

@manatwork trình tự đối chiếu của bạn có thể cho phép phạm vi ....
derobert

Tôi không biết nhiều về đối chiếu. Ý bạn là LC_COLLATE="en_US.UTF-8"sao?
manatwork

@manatwork Tôi đã chỉnh sửa câu hỏi để đưa ra một ví dụ. Lưu ý rằng nó có thể khác trên hệ thống của bạn, bởi vì đôi khi các chuỗi đối chiếu (sắp xếp) đó thay đổi.
derobert

1
@manatwork Không sao, tôi gần như đã nộp báo cáo lỗi trước khi tôi nhận thấy nỗ lực trốn thoát -...
derobert

4

Quy tắc chung với regexps (và bất kỳ lỗi nào trong các đoạn mã lớn hơn): cắt nó xuống và xây dựng lại từng bước hoặc sử dụng bisecting - bất cứ điều gì tốt hơn cho bạn.

Trong trường hợp này, thủ phạm hóa ra là dấu gạch dưới - thoát khỏi nó bằng dấu gạch chéo ngược đã làm cho nó hoạt độ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.