Biểu thức thông thường sử dụng \ vs sử dụng \


10

Tại sao

grep e\\.g\\. <<< "this is an e.g. wow"

grep e\.g\. <<< "this is an e.g. wow"

Làm điều tương tự?

Nếu tôi thêm một dấu gạch chéo thứ ba, nó cũng có kết quả tương tự. NHƯNG, một khi tôi thêm một dấu gạch chéo thứ tư, nó không còn hoạt động. Điều này có liên quan đến một câu hỏi từ một bài kiểm tra cũ cho một lớp học. Nó hỏi liệu cái có hai dấu gạch chéo ngược có hoạt động để xuất dòng với "vd" ban đầu tôi nghĩ nó không hoạt động, nhưng tôi đã cố gắng đảm bảo và nó đã làm được. Giải thích là gì?


Tôi đã nghĩ bash sẽ lấy \\\.và đưa grep \.nhưng không được. câu hỏi hay

Câu trả lời:


9

Đầu tiên, lưu ý rằng dấu gạch chéo đơn khớp quá nhiều:

$ echo $'eegg \n e.g.' | grep e\.g\.
eegg
 e.g.

Theo như Bash có liên quan, một khoảng thời gian thoát cũng giống như một khoảng thời gian. Bash vượt qua giai đoạn để grep . Đối với grep, một khoảng thời gian phù hợp với bất cứ điều gì.

Bây giờ, hãy xem xét:

$ echo $'eegg \n e.g.' | grep e\\.g\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\.g\\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\\.g\\\\.
$

Khi Bash nhìn thấy một dấu gạch chéo kép, sẽ giảm nó thành một dấu gạch chéo và chuyển nó vào grep, trong lần đầu tiên trong ba thử nghiệm ở trên, sẽ thấy, như chúng ta muốn, một dấu gạch chéo trước một khoảng thời gian. Vì vậy, điều này làm đúng.

Với một dấu gạch chéo ba, Bash giảm hai dấu đầu tiên thành một dấu gạch chéo. Sau đó nó thấy \.. Vì một thời kỳ trốn thoát không có ý nghĩa đặc biệt với Bash, nên điều này được giảm xuống thành một thời kỳ đơn giản. Kết quả là grep thấy, như chúng ta muốn, một dấu gạch chéo trước một khoảng thời gian.

Với bốn dấu gạch chéo, Bash giảm mỗi cặp thành một dấu gạch chéo. Bash truyền lại cho grep hai dấu gạch chéo và một khoảng thời gian. grep nhìn thấy hai dấu gạch chéo và dấu chấm và giảm hai dấu gạch chéo thành một dấu gạch chéo theo nghĩa đen . Trừ khi đầu vào có một dấu gạch chéo theo sau bởi bất kỳ ký tự nào, không có kết quả khớp.

Để minh họa điều cuối cùng, hãy nhớ rằng bên trong dấu ngoặc đơn, tất cả các ký tự đều theo nghĩa đen. Do đó, với ba dòng đầu vào sau, lệnh grep chỉ khớp với dòng có dấu gạch chéo trong đầu vào:

$ echo 'eegg
e.g.
e\.g\.' |  grep e\\\\.g\\\\.
e\.g\.

Tóm tắt hành vi của Bash

Đối với Bash, các quy tắc là

  • Hai dấu gạch chéo được giảm xuống một dấu gạch chéo.

  • Một dấu gạch chéo trước một ký tự bình thường, giống như một dấu chấm, chỉ là ký tự bình thường (dấu chấm).

Như vậy:

$ echo \. \\. \\\. \\\\.
. \. \. \\.

Có một cách đơn giản để tránh tất cả sự nhầm lẫn này: trên dòng lệnh Bash, các biểu thức thông thường nên được đặt trong dấu ngoặc đơn. Trong dấu ngoặc đơn, Bash để mọi thứ một mình.

$ echo '\. \\. \\\. \\\\.'  # Note single-quotes
\. \\. \\\. \\\\.

Câu hỏi: Phải mất hai dấu gạch chéo ngược để bash xem nó là dấu gạch chéo ngược (một là chuỗi thoát, hai là dấu gạch chéo ngược theo nghĩa đen). Vì vậy, khi có 3 bash có coi straggler thứ ba là một chuỗi thoát không? Vì nó không thoát được gì, nên nó có bị loại bỏ không?
Franz Kafka

@DanielAmaya Người thứ ba được coi là một lối thoát cho nhân vật tiếp theo. Trong trường hợp của chúng tôi, nhân vật đó là thời kỳ và, đối với bash (không giống như grep), một khoảng thời gian thoát chỉ là một khoảng thời gian đơn giản. bash sau đó vượt qua giai đoạn đơn giản để grep.
John1024

@DanielAmaya Xem câu trả lời cập nhật cho một echotuyên bố minh họa những gì bash làm trong những trường hợp này.
John1024

2
@DanielAmaya Trong cả hai trường hợp, bash làm giảm hai dấu gạch chéo đầu tiên thành một dấu gạch chéo. Những gì còn lại là \.hoặc .. Đối với bash, cả hai đều giống nhau: chúng tương đương với một khoảng thời gian đơn giản. Do đó, về tổng thể, những gì bash cung cấp cho grep là giống nhau cho cả hai: một dấu gạch chéo theo sau là một dấu chấm.
John1024

1
Chỉ là một bổ sung nhỏ - sử dụng echokhông phải là cách rất đáng tin cậy để kiểm tra regrec vì có nhiều triển khai chương trình này. Ví dụ, dưới zsh của tôi (echo tích hợp) echo \. \\. \\\. \\\\. \\\\\.cho . \. \. \. \., nhưng /bin/echo \. \\. \\\. \\\\. \\\\\.trả về . \. \. \\. \\.. Một cái gì đó giống như printf "%s" ...có lẽ là cách tốt hơn.
jimmij

4

Đầu ra chỉ giống nhau cho chuỗi của bạn, nhưng nói chung các biểu thức chính quy đó làm những việc khác nhau. Hãy thay đổi ví dụ của bạn một chút bằng cách thêm mô hình thứ hai e,g,(với hôn mê), thứ ba e\.g\.(dấu chấm), thứ tư e\,g\,(hôn mê), và -otùy chọn để grep để in phần chỉ phù hợp.

  • Trong trường hợp sau đây .phù hợp với bất kỳ char nào (thông báo ''xung quanh e.g., tôi sẽ đến đó sau)

    $ grep -o 'e.g.' <<< grep -o 'e.g.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
    e,g,
    
  • Tiếp theo chúng ta thoát .với dấu gạch chéo ngược \, vì vậy chỉ có nghĩa đen .sẽ được khớp:

    $ grep -o 'e\.g\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
    
  • Nhưng chúng ta có thể trốn thoát \với người khác \, do đó nghĩa đen \sẽ được kết hợp theo sau .(tức là bất kỳ char nào):

    $ grep -o 'e\\.g\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.
    e\,g\,
    
  • Nhưng nếu chúng ta chỉ muốn khớp mà \.không cần \,một cái khác \để thoát khỏi ý nghĩa đặc biệt của dấu chấm:

    $ grep -o 'e\\\.g\\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.
    

Bây giờ, vì bạn không sử dụng ''xung quanh đối số grep, bạn cần thêm một dấu gạch chéo ngược khác để thoát dấu gạch chéo ngược từ giải thích shell, vì vậy:

grep 'e\.g\.'     => grep e\\.g\\.
grep 'e\\.g\\.'   => grep e\\\\.g\\\\.  (each backslash has to be quoted separately)
grep 'e\\\.g\\\.' => grep e\\\\\\.g\\\\\\. (3 x 2 = 6 backslashes in total)

3

Khi bạn thực hiện một grep e\.g\., shell đang sử dụng dấu gạch chéo ngược, do đó bạn đang thực hiện một grep e.g., phù hợp. Khi bạn thực hiện một grep e\\.g\\., vỏ một lần nữa tiêu thụ một dấu gạch chéo, và bây giờ bạn đang làm một grep e\.\g., một lần nữa phù hợp. Bây giờ, một dấu gạch chéo ngược vào vỏ trông như thế nào \\. Vì vậy, khi bạn có \\, cái đầu tiên là một chuỗi thoát, thứ hai là một dấu gạch chéo ngược theo nghĩa đen. Khi bạn thực hiện một grep e\\\.g\\\., nó vẫn kết thúc grep e\.\g., bởi vì không có một chuỗi thoát ( \) trước lần đầu tiên \để biến nó thành một nghĩa đen \. Hãy ghi nhớ \ là dấu gạch chéo ngược, do đó grep e\\\\.\\\\gkết thúc là grep e\\.g\\., điều này rõ ràng không phù hợp.

Để xem cách vỏ được nhìn thấy những gì bạn đang làm, sử dụng echo (ví dụ, echo grep e\\.g\\. <<< "this is an e.g. wow"vs echo grep e\\\\.g\\\\. <<< "this is an e.g. wow")


0

Hai lệnh tạo ra cùng một đầu ra chỉ cho đầu vào của bạn nhưng nếu không thì chúng khác nhau. Để hiểu những gì đang diễn ra, chúng ta phải biết làm thế nào thông số được diễn giải trước bashvà sau đó grep.

Chạy trốn trong bash

\là một nhân vật đặc biệt hủy bỏ ý nghĩa đặc biệt của nhân vật sau bao gồm cả \chính nó. Nếu ký tự sau không có ý nghĩa đặc biệt thì nó được thông qua mà không thay đổi. Ví dụ với lệnh và kết quả:

  • echo \a: a- nhân vật bình thường thoát ra cho nhân vật
  • echo \\: \- nhân vật đặc biệt thoát được cho nhân vật
  • echo \\\a: \a- sự kết hợp đặc biệt, thông thường
  • echo \\\\: \\- sự kết hợp đặc biệt, đặc biệt

echosẽ in chuỗi kết quả sau khi bashgiải thích nó. Thông tin thêm: tài liệu bash , hacker bash wiki , POSIX đặc điểm kỹ thuật .

.không có ý nghĩa đặc biệt trong bash. Đó là một nhân vật bình thường cho vỏ. Dưới đây là các trình tự liên quan đến ví dụ của bạn:

  • echo .: .
  • echo \.: .
  • echo \\.: \.
  • echo \\\.: \.
  • echo \\\\.: \\.

Giải pháp đơn giản hơn cho chuỗi ký tự trong bash

Để truyền tham số theo nghĩa đen của bashbạn, bạn có thể sử dụng 'thoát trích dẫn duy nhất . Giữa các trích dẫn đơn, bạn không cần phải quan tâm đến ý nghĩa đặc biệt của các ký tự vì trích dẫn đơn là ký tự duy nhất có ý nghĩa đặc biệt ở đó. Bạn có thể chèn một trích dẫn sau khi kèm theo phần đầu tiên của chuỗi. Ví dụ
echo 'part1'\''part2':: part1'part2

Regex trong grep

\là một nhân vật thoát với ý nghĩa tương tự như trong bash. .là một nhân vật đặc biệt đại diện cho một lần xuất hiện của bất kỳ nhân vật nào . Xem: regex POSIX , regex GNU grep . Ví dụ về biểu thức regex:

  • .- phù hợp với bất kỳ nhân vật nào như ahoặc.
  • \.- chỉ khớp theo .nghĩa đen

Ví dụ của bạn

Trên dòng thứ hai của tất cả các ví dụ dưới đây bạn sẽ tìm thấy tương đương với dấu nháy đơn 'hiển thị mà chuỗi chữ được thông qua bashđể grep. Sau đó, sau khi grepthực hiện thoát khỏi ký tự đặc biệt duy nhất có thể có trong các ví dụ là .khớp với bất kỳ ký tự nào. Trên dòng thứ ba có một mô tả những gì biểu thức phù hợp.

  • grep e.g. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    ebất kỳ ký tự nào bất kỳ ký tự gnào - khớp e.g.và có thể các chuỗi khác nhưeagb
  • grep e\.g\. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    ebất kỳ ký tự nào bất kỳ ký tự gnào - khớp e.g.và có thể các chuỗi khác nhưexgy
  • grep e\\.g\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.theo nghĩa đen - chỉ khớpe.g.
  • grep e\\\.g\\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.theo nghĩa đen - chỉ khớpe.g.
  • grep e\\\\.g\\\\. <<< "this is an e.g. wow"
    grep 'e\\.g\\.' <<< "this is an e.g. wow"
    e\bất kỳ nhân vật nào bất kỳ nhân vật g\nào - không phù hợpe.g.
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.