2009-07-23 26 views
91

Tôi đang sử dụng egrep -R theo sau là một biểu thức chính quy có chứa khoảng 10 đoàn thể, do đó, như: .jpg | .png | .gif vv Điều này hoạt động tốt, bây giờ tôi muốn thay thế tất cả các chuỗi tìm thấy với .bmpSử dụng sed và grep để tìm kiếm và thay thế

tôi đã nghĩ đến một cái gì đó giống như

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form 

vì vậy vấn đề ở đây là làm thế nào để làm một đoàn biểu thức chính quy tương tự trong sed và làm thế nào để tôi nói với nó để lưu các thay đổi đối với tập tin mà nó có đầu vào từ.

+2

Tôi tìm thấy câu hỏi này trong khi tìm kiếm cách để tìm kiếm và thay thế trên nhiều tập tin trong một hệ thống phân cấp thư mục. Đối với những người khác trong tình huống của tôi, hãy thử [rpl] (http://freshmeat.net/projects/rpl/). – titaniumdecoy

+0

cảm ơn bạn rpl hoạt động và thực sự dễ nhớ .. chỉ cần rpl old_string new_string target_files. – cesarpachon

Trả lời

174

Sử dụng lệnh này:

egrep -lRZ "\.jpg|\.png|\.gif" . \ 
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g' 
  • egrep: tìm phù hợp với dây chuyền sử dụng biểu thức chính quy mở rộng

    • -l: chỉ danh sách phù hợp với tên tập tin

    • -R: tìm kiếm đệ quy qua tất cả các thư mục cho

    • -Z: sử dụng \0 như kỷ lục tách

    • "\.jpg|\.png|\.gif": phù hợp với một trong những chuỗi ".jpg", ".gif" hoặc ".png"

    • .: bắt đầu tìm kiếm trong thư mục hiện

  • xargs: thực thi một lệnh với stdin như là đối số

    • -0: sử dụng \0 như kỷ lục phân cách. Điều này rất quan trọng để khớp với số -Z của egrep và để tránh bị lừa bởi dấu cách và dòng mới trong tên tệp đầu vào.

    • -l: sử dụng một dòng cho mỗi lệnh như tham số

  • sed: các s tream ed itor

    • -i: thay thế các tập tin đầu vào với đầu ra mà không cần sao lưu

    • -e: dùng tham số sau đây là biểu hiện

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': thay thế tất cả các lần xuất hiện của chuỗi ".jpg", ".gif" hoặc ".png" với ".bmp"

+0

tất cả đều hoạt động ngoại trừ | trong phần sed. Tôi không hiểu tại sao mặc dù vì nó có ý nghĩa ... phần -l của xargs đã cho tôi lỗi vì vậy tôi lấy nó ra, có thể có liên quan? – Ori

+0

Tôi thấy rằng lệnh này thêm một dòng mới vào cuối tất cả các tệp mà nó xử lý. – titaniumdecoy

+0

@titanumdecoy: Tôi không thể tái tạo hành vi này. bạn sử dụng phiên bản sed nào và hệ điều hành nào là bạn? –

11

Thành thật mà nói, nhiều như tôi thích sed cho các nhiệm vụ thích hợp, điều này chắc chắn là một nhiệm vụ cho perl - nó thực sự mạnh mẽ hơn cho loại một lót, đặc biệt là "viết nó trở lại nơi nó đến từ" -i chuyển đổi hiện nó cho bạn, và tùy chọn cũng cho phép bạn giữ phiên bản cũ xung quanh ví dụ như với một .bak nối, chỉ cần sử dụng -i.bak thay thế).

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/ 

chứ không phải là công việc phức tạp trong sed (nếu thậm chí có thể có) hoặc awk ...

+6

sed sử dụng -i, giống như perl. – Stobor

+0

@Stobor - Tôi thề rằng tôi đã gặp vấn đề khi hoạt động perl khi tôi cho chuỗi thay thế regex thực hiện chính xác những gì tôi muốn, không giống như sed, ngay cả khi tôi đưa ra tùy chọn regex để 'sed' .. Tôi nghĩ mình đã quên cờ để sed hoặc nó có những hạn chế. –

0

thử một cái gì đó sử dụng một vòng lặp for

for i in `egrep -lR "YOURSEARCH" .` ; do echo $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done 

không đẹp, nhưng nên làm.

+3

xargs chắc chắn là phù hợp hơn ở đây. –

+1

và sử dụng mẫu '| trong khi đọc i' sẽ bật phát trực tuyến và tránh giới hạn độ dài khi kết quả của egrep quá dài –

5

Tôi không thể nhận bất kỳ lệnh nào trên trang này hoạt động cho tôi: số sed solution thêm dòng mới vào cuối tất cả các tệp được xử lý và perl solution không thể chấp nhận đủ đối số để tìm. Tôi tìm thấy giải pháp này mà hoạt động hoàn hảo:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g' 

này sẽ recurse xuống cây thư mục hiện hành và thay thế search_regex với replacement_string trong bất kỳ tập tin kết thúc bằng .h hoặc .m.

Tôi cũng đã sử dụng rpl cho mục đích này trong quá khứ.

9

Một cách khác để làm điều này

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \; 

Một số trợ giúp về các lệnh trên

Phát hiện sẽ làm tìm cho bạn trên thư mục hiện hành chỉ định bởi .

-name tên của tập tin trong trường hợp của tôi pom.xml của nó có thể cung cấp thẻ hoang dã.

-exec thực hiện

sed biên tập dòng

-i bỏ qua trường hợp

s là cho thay

/4.6.0.../ String để được tìm kiếm

/5.0.0.../ String để được thay thế

+0

có lẽ không quá mạnh - nhưng điều này dễ hiểu hơn nhiều so với câu trả lời được chấp nhận – icc97

0

Trường hợp sử dụng của tôi là tôi muốn thay thế foo:/Drive_Letter bằng foo:/bar/baz/xyz Trong trường hợp của tôi, tôi có thể làm điều đó bằng mã sau. Tôi đã ở cùng một vị trí thư mục nơi có nhiều tệp.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g' 

hy vọng điều đó sẽ hữu ích.

CẬP NHẬT s | foo:/Drive_letter: | foo:/ba/baz/xyz | g

+0

Bạn có thể sử dụng các dấu tách khác cho lệnh sed, và làm như vậy làm cho pathnames đẹp hơn nhiều: 'sed 's | foo:/Drive_letter: | foo:/ba/baz/xyz | g'' – Kevin

Các vấn đề liên quan