Tìm kiếm không phân biệt chữ hoa chữ thường và thay thế bằng sed


81

Tôi đang cố gắng sử dụng SED để trích xuất văn bản từ tệp nhật ký. Tôi có thể thực hiện tìm kiếm và thay thế mà không gặp quá nhiều khó khăn:

sed 's/foo/bar/' mylog.txt

Tuy nhiên, tôi muốn làm cho tìm kiếm không phân biệt chữ hoa chữ thường. Từ những gì tôi đã tìm kiếm trên Google, có vẻ như việc nối ivào cuối lệnh sẽ hoạt động:

sed 's/foo/bar/i' mylog.txt

Tuy nhiên, điều này cho tôi một thông báo lỗi:

sed: 1: "s/foo/bar/i": bad flag in substitute command: 'i'

Có gì sai ở đây và làm cách nào để khắc phục?


2
Bạn có thể thử cập nhật bản sao sed của mình không? Ilà một tiện ích mở rộng GNU có thể không có sẵn với bản sao sed.
Lazer 10/12/10

4
CHỈNH SỬA : Tôi đã vượt qua chứng chỉ OS X, vì OP đã chấp nhận một câu trả lời không hoạt động trên OS X. (Như một câu trả lời khác đã chỉ ra, sed trên OS X không hỗ trợ đối sánh phân biệt chữ hoa chữ thường, trái với tài liệu của Apple.)
danorton

1
@danorton: Cảm ơn vì điều đó; trong trường hợp bạn có cảm giác rằng tài liệu của Apple hứa hẹn điều gì đó mà việc triển khai không mang lại từ câu trả lời của tôi dưới đây: man sedLÀ phù hợp với việc triển khai - không đề cập đến (và không hỗ trợ trong thực tế) cho đối sánh không phân biệt chữ hoa chữ thường; nếu bạn tìm thấy một phần tài liệu tuyên bố khác, vui lòng cho chúng tôi biết.
mklement0

1
@ mklement0, vâng, xin lỗi, tôi đã sửa. Tài liệu của Apple không đưa ra bất kỳ tuyên bố nào về việc đối sánh không phân biệt chữ hoa chữ thường cho sed.
danorton

1
FWIW, các phiên bản GNU của các công cụ có phiên bản BSD đi kèm với OS X có sẵn từ các trình quản lý gói khác nhau. Tôi đã cài đặt bộ tiện ích văn bản đầy đủ qua Homebrew với gtiền tố, vì vậy tôi có thể sử dụng gsedhoặc gdatekhi tôi cần một tính năng không có trong phiên bản stock.
Mark Reed vào

Câu trả lời:


72

Nói rõ hơn: Trên macOS - kể từ Mojave (10.14) - sed- là triển khai BSD - KHÔNG hỗ trợ đối sánh không phân biệt chữ hoa chữ thường - khó tin nhưng là sự thật. Các câu trả lời trước đây được chấp nhận , mà tự nó cho thấy một GNU sed lệnh, đạt được trạng thái mà vì perlgiải pháp dựa trên đề cập trong các ý kiến.

Để làm cho giải pháp Perl đó cũng hoạt động với các ký tự nước ngoài , thông qua UTF-8, hãy sử dụng một cái gì đó như:

perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo"
  • -C bật hỗ trợ UTF-8 cho các luồng và tệp, giả sử ngôn ngữ hiện tại là dựa trên UTF-8.
  • -Mutf8 bảo Perl giải thích mã nguồn là UTF-8 (trong trường hợp này là chuỗi được chuyển tới -pe) - đây là cách tương đương ngắn hơn với câu cảm ơn dài dòng hơn -e 'use utf8;'., Mark Reed

(Lưu ý rằng việc sử dụng awkcũng không phải là một tùy chọn , vì awktrên macOS (tức là BWK awk , hay còn gọi là BSD awk ) dường như hoàn toàn không biết về ngôn ngữ - tolower()và các toupper()chức năng của nó bỏ qua các ký tự nước ngoài (và sub()/gsub() không có cờ phân biệt chữ hoa chữ thường để bắt đầu với).)



69

Lưu ý của người biên tập : Giải pháp này không hoạt động trên macOS (ngoài hộp), vì nó chỉ áp dụng cho GNU sed , trong khi macOS đi kèm với BSD sed .

Viết hoa chữ 'I'.

sed 's/foo/bar/I' file

2
Tôi cũng thấy điều này và đã thử nó ... nhưng tôi vẫn nhận được thông báo lỗi tương tự.
Craig Walker

15
Có vẻ như BSD sed có rất nhiều hạn chế. Tôi sẽ làm điều này trong PERL (tức là perl -pe 's / foo / bar / i'), nếu đúng như vậy.
Wesley Rice

3
Các cài đặt mặc định của OS X Lion cung cấp cho các lỗi: sed: 1: "s / foo / bar / I": cờ xấu trong lệnh thay thế: 'Tôi'
Ben Clayton

13
Các Ihậu tố không phải là một sử dụng di động của sed. POSIX sedchỉ sử dụng Biểu thức chính quy Cơ bản (BRE), những biểu thức này có giới hạn đáng ngạc nhiên. Họ thậm chí không hỗ trợ +(bạn phải sử dụng \{1,\}thay thế), hãy để một mình đối sánh không phân biệt chữ hoa chữ thường. Cách di động duy nhất để làm điều đó với sed là kiểm tra một cái gì đó giống như /[hH][eE][lL][lL][oO]/, điều này thường sẽ không thực tế.
edam

5
Điều đó cần phải được cải thiện, /gInó sẽ chỉ hoạt động trong trận đấu đầu tiên.
Faheem Mitha

25

Một công việc khác sedtrên Mac OS X là cài đặt gsedtừ MacPorts hoặc HomeBrew và sau đó tạo bí danh sed='gsed'.


gsed "s / a / b / Ig" hoạt động, cảm ơn! Tại sao một câu trả lời hoạt động tốt lại nhận được phản đối?
Matthias M

3
câu trả lời này là tuyệt vời. được sử dụng brew install gnu-sedsau đó chuyển đến ~ / .bash_profile của tôi và thêm bí danh. Cảm ơn @davmat
ThinkBonobo

8
Tốt hơn nên làm brew install gnu-sed --with-default-names- điều này sẽ ghi đè mặc định sed.
Mar0ux

4

Câu hỏi thường gặp về sed giải quyết tìm kiếm không phân biệt chữ hoa chữ thường có liên quan chặt chẽ . Nó chỉ ra rằng a) nhiều phiên bản sed hỗ trợ một cờ cho nó và b) thật khó xử trong sed, bạn nên sử dụng awk hoặc Perl.

Nhưng để làm điều đó trong POSIX sed, họ đề xuất ba tùy chọn (được điều chỉnh để thay thế ở đây):

  1. Chuyển sang chữ hoa và lưu dòng gốc trong không gian lưu giữ; Tuy nhiên, điều này sẽ không hoạt động đối với các nội dung thay thế, vì nội dung gốc sẽ được khôi phục trước khi in, vì vậy nó chỉ tốt cho việc chèn hoặc thêm các dòng dựa trên khớp không phân biệt chữ hoa chữ thường.

  2. Có thể các khả năng bị giới hạn ở FOO, Foofoo. Những điều này có thể được bao phủ bởi

    s/FOO/bar/;s/[Ff]oo/bar/
    
  3. Để tìm kiếm tất cả các kết quả phù hợp có thể có, người ta có thể sử dụng biểu thức dấu ngoặc cho mỗi ký tự:

    s/[Ff][Oo][Oo]/bar/
    

1

Phiên bản Mac của sedcó vẻ hơi hạn chế. Một cách để giải quyết vấn đề này là sử dụng vùng chứa linux (thông qua Docker) có phiên bản có thể sử dụng là sed:

cat your_file.txt | docker run -i busybox /bin/sed -r 's/[0-9]{4}/****/Ig'

15
đây là một điều đặc biệt nguy hiểm phải làm. Nếu bất cứ ai thậm chí đang xem xét điều này một cách nghiêm túc, chỉ cần cài đặt một GNU sed cục bộ.
ocodo

Cách tiếp cận chung quá mức cần thiết nhưng hữu ích cần biết!
YvesgereY

1

Nếu bạn đang thực hiện đối sánh mẫu trước, ví dụ:

/pattern/s/xx/yy/g

thì bạn muốn đặt Isau mẫu:

/pattern/Is/xx/yy/g

Thí dụ:

echo Fred | sed '/fred/Is//willma/g'

trả lại willma; nếu không có I, nó trả về chuỗi không được chạm ( Fred).


2
Trên MacOs, tôi nhận được:sed: 1: "/fred/Is//willma/g": invalid command code I
Chris F Carroll,

Mẹo tốt. Đây là cách tôi sử dụng nó trên một tìm kiếm phức tạp: sed -r '/'"$PATTERN"'/I,${s//'$YELLOW'&'$NO_COLOR'/g;b};$q3'. Nó in văn bản và nếu tìm thấy mẫu (không phân biệt chữ hoa chữ thường), nó sẽ đánh dấu văn bản bằng màu vàng (màu ansi). Nếu không tìm thấy - trả về mã thoát 3.
Noam Manos

0

Tôi cũng có nhu cầu tương tự và nghĩ ra điều này:

lệnh này để đơn giản tìm tất cả các tệp:

grep -i -l -r foo ./* 

cái này để loại trừ this_shell.sh (trong trường hợp bạn đặt lệnh trong một tập lệnh có tên this_shell.sh ), đưa đầu ra cho bảng điều khiển để xem điều gì đã xảy ra và sau đó sử dụng sed trên mỗi tên tệp được tìm thấy để thay thế văn bản foo bằng thanh :

grep -i -l -r --exclude "this_shell.sh" foo ./* | tee  /dev/fd/2 | while read -r x; do sed -b -i 's/foo/bar/gi' "$x"; done 

Tôi đã chọn phương pháp này, vì tôi không muốn thay đổi tất cả các dấu thời gian cho các tệp không được sửa đổi. việc cung cấp kết quả grep chỉ cho phép các tệp có văn bản đích được xem xét (do đó có khả năng cũng cải thiện hiệu suất / tốc độ)

Đảm bảo sao lưu các tệp của bạn và kiểm tra trước khi sử dụng. Có thể không hoạt động trong một số môi trường đối với các tệp có không gian nhúng. (?)


0

Sử dụng sau để thay thế tất cả các lần xuất hiện: sed 's / foo / bar / gI' mylog.txt


Xem stackoverflow.com/a/4412964/4294399 , bao gồm thủ đô I. Tôi cũng không nghĩ rằng điều này thực sự trả lời câu hỏi vì nó không hỏi về sự thay thế toàn cầu.
Calculuswhiz
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.