2010-12-10 13 views
60

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ìm kiếm phân biệt chữ hoa chữ thường và thay thế bằng sed

tôi có thể thực hiện tìm kiếm và thay thế mà không cần quá nhiều rắc rối:

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

Tuy nhiên, tôi muốn làm cho việc tìm kiếm case-insensitive. Từ những gì tôi đã googled, có vẻ như phụ "i" để kết thúc lệnh nên làm việc:

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

Tuy nhiên, điều này mang lại 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 thế nào để sửa nó?

Tôi đang sử dụng OS X, trong trường hợp nó quan trọng.

+0

Bạn đã thử vốn 'I'? – Lazer

+0

@Lazer: Tôi đã làm, nhưng nó không hoạt động. Đó là stumped tôi đủ rằng tôi đang gửi một lời cầu xin để được giúp đỡ về SO. :-( –

+2

Bạn có thể thử cập nhật bản sao của sed? 'I' là một phần mở rộng GNU có thể không có sẵn với bản sao của bạn sed. – Lazer

Trả lời

53

Để được rõ ràng: Trên MacOS (OS X) - như Sierra (10.12) - sed - đó là BSD thực hiện - KHÔNG hỗ trợ case-insensitive phù hợp với - khó tin nhưng đúng. formerly accepted answer, chính nó hiển thị lệnh GNUsed, đã đạt được trạng thái đó vì giải pháp dựa trên perl được đề cập trong các nhận xét.

Để làm cho điều đó giải pháp Perl làm việc với nhân vật nước ngoài là tốt, qua UTF-8, sử dụng một cái gì đó như:

perl -C -Mutf8 -pe 's/öœ/oo/i' <<< "FÖŒ" # -> "Foo" 
  • -C bật UTF-8 hỗ trợ cho các con suối và các tập tin, giả sử miền địa phương hiện tại là UTF-8.
  • -Mutf8 nói Perl để giải thích mã nguồn như UTF-8 (trong trường hợp này, chuỗi truyền cho -pe) - đây là tương đương ngắn hơn của tiết hơn -e 'use utf8;' - cảm ơn, @ Mark Reed.

(Lưu ý rằng sử dụng awk không phải là một lựa chọn một trong hai, như awk trên OS X (ví dụ, BWK awk, aka BSD awk) dường như là hoàn toàn không biết gì về miền địa phương hoàn toàn - nó tolower() và Các chức năng toupper() 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).

+0

Trên dòng lệnh 'perl', bạn luôn có thể sử dụng' -mblah' nstead của '-e 'sử dụng blah''. –

+0

Typo - phải là chữ hoa để chữ cái này hoạt động. 'perl -C -Mutf8 -pe 's/öœ/oo/i' <<<" FÖŒ "# => Foo' –

+0

@MarkReed: Cảm ơn - Tôi đã cập nhật câu trả lời. – mklement0

52

Viết hoa 'I'.

sed 's/foo/bar/I' file 
+2

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

+13

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

+0

Lệnh perl của bạn hoạt động. Tôi sẽ cung cấp cho bạn một upvote cho điều đó. –

1

Phiên bản Mac sed có vẻ hơi bị hạn chế.Một cách để làm việc xung quanh này là sử dụng một container Linux (thông qua Docker) trong đó có một phiên bản sử dụng được của sed:

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

đây là một điều đặc biệt ghê gớm. Nếu bất cứ ai thậm chí còn xem xét việc này nghiêm túc, chỉ cần cài đặt một GNU sed cục bộ. – ocodo

17

Một công việc xung quanh cho sed trên Mac OS X là cài đặt gsed từ MacPorts hoặc homebrew và sau đó tạo bí danh sed='gsed'.

+0

gsed "s/a/b/Ig" hoạt động, cảm ơn! Tại sao một câu trả lời làm việc tốt nên có được một lời bình luận? –

+2

câu trả lời này là rất tốt. sử dụng 'brew install gnu-sed' sau đó đi đến ~/.bash_profile của tôi và thêm bí danh. Cảm ơn @davmat – ThinkBonobo

+5

Tốt hơn để làm 'brew install gnu-sed --với tên mặc định - điều này sẽ ghi đè lên' sed' mặc định. – Mar0ux

-2

sed 's/string1/string2/Ig' Capital I là một tùy chọn hữu ích cho việc tìm kiếm chuỗi không phân biệt chữ hoa chữ thường.

0

Tôi đã có một nhu cầu tương tự, và đến với điều này:

lệnh này chỉ đơn giản là tìm tất cả các file:

grep -i -l -r foo ./* 

một này để loại trừ this_shell.sh (trong trường hợp bạn đặt lệnh trong một kịch bản gọi là this_shell.sh), tee đầu ra để giao diện điều khiển để xem những gì đã xảy ra, và sau đó sử dụng sed trên mỗi tên tập tin tìm thấy để thay thế foo văn bản với 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 thích có tất cả các dấu thời gian đã thay đổi đối với các tệp không được sửa đổi. cho kết quả grep chỉ cho phép các tệp có văn bản đích được xem xét (do đó có thể cải thiện hiệu suất/tốc độ)

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

0

Nếu bạn đang làm mô hình kết hợp đầu tiên ví dụ/mô hình/s/xx/yy/g

sau đó bạn muốn đặt chữ "I" sau khi mô hình/mô hình/Is/xx/yy/g

ví dụ: echo Fred | sed '/ fred/Is // willma/g' trả về willma ... mà không có tôi trả về chuỗi bị ảnh hưởng (Fred)