2010-01-21 31 views
32

tôi phát hiện ra về lệnh thay Vim của ...Làm thế nào tôi có thể tìm kiếm và thay thế đệ quy trong một thư mục trong Vim?

:%s/replaceme/replacement/gi 

Và vimgrep ...

:vimgrep /findme/gj project/**/*.rb 

Có cách nào để kết hợp chúng theo thứ tự để làm một sự thay thế trên tất cả các file dưới một danh mục?

+0

[Ở đây] (http: // stackoverflow.com/a/13944042/834176) là một cách để tìm kiếm và thay thế đệ quy, nhưng chỉ trên các tệp dưới sự kiểm soát phiên bản (nó có thể được tổng quát dễ dàng nếu bạn thực sự muốn tìm kiếm * tất cả * tệp trong thư mục). –

Trả lời

47

Mặc dù tôi là người dùng Vim, tôi thường sử dụng findsed cho loại điều này. Cú pháp regex cho sed tương tự như Vim (cả hai đều là hậu duệ của ed), mặc dù không giống nhau. Với GNU sed bạn cũng có thể sử dụng -i để chỉnh sửa tại chỗ (thông thường sed phát ra phiên bản đã sửa đổi thành giá trị chuẩn).

Ví dụ:

find proj -name '*.rb' -type f -exec sed -i -e 's/regex/replacement/g' -- {} + 

Từng mảnh:

  • proj = tìm kiếm trong cây "Proj"
  • -name '*.rb' = cho những thứ có tên trận đấu '* rb'
  • -type f = và là các tệp thông thường (không phải thư mục, đường ống, liên kết tượng trưng, ​​v.v.)
  • -exec sed = chạy sed với những lập luận này:
    • -i = với tại chỗ chỉnh sửa
    • -e 's/regex/replacement/g' = thực hiện một "thay thế" lệnh (mà gần giống như Vim của :s, nhưng lưu ý thiếu % - đó là mặc định trong sed)
    • -- = cuối cờ, tên tập tin bắt đầu ở đây
    • {} = này cho find rằng th e tên tập tin nó tìm thấy nên được đặt trên dòng lệnh của sed ở đây
    • + = điều này cho biết find rằng hành động -exec được hoàn thành và chúng tôi muốn nhóm các đối số vào càng ít càng tốt (thường hiệu quả hơn chạy nó một lần cho mỗi tên tệp). Để chạy nó một lần cho mỗi tên tệp, bạn có thể sử dụng \; thay vì +.

Đây là giải pháp chung với GNU sedfind. Điều này có thể được rút ngắn một chút trong trường hợp đặc biệt. Ví dụ: nếu bạn biết rằng mẫu tên của mình sẽ không khớp với bất kỳ thư mục nào bạn có thể bỏ qua -type f. Nếu bạn biết rằng không có tệp nào của bạn bắt đầu bằng số -, bạn có thể bỏ qua --. Here's an answer I posted to another question with more details on passing filenames found with find to other commands.

+6

Hãy chắc chắn và kiểm tra 'tìm kiếm' của bạn trước khi đưa nó vào' sed' - điều này có thể thực sự tồi tệ nếu nó quá bao hàm. Nó cũng là một ý tưởng tốt để cung cấp cho 'sed' tùy chọn' -c' ('--copy'), điều này sẽ ngăn không cho nó lộn xộn với các tệp chỉ đọc. – Cascabel

+0

@BroSlow Đủ công bằng. Tôi đã cập nhật câu trả lời để an toàn hơn/tổng quát hơn. (Điều đó nói rằng, trên Linux ít nhất ARG_MAX là khá lớn, và đối với trường hợp sử dụng được mô tả trong câu hỏi, tên tập tin có dấu cách hoặc các ký tự đặc biệt sẽ khá lạ.) –

+0

Nếu bạn sử dụng phương pháp này, bạn không thể sử dụng cấu hình không hỗ trợ nó, bạn có thể sử dụng 'vim -c '%/regex/thay thế/gc' -c 'wq' - {} \;' theo cách đó bạn có thể xác nhận các thay đổi của bạn cũng – Funonly

4

Có một plugin cố gắng để làm điều đó: Vimgrep Replace.

Ồ, chờ ... có những người khác: Global Replace, EasyGrep.

Đối với giải pháp không có plugin, có lẽ argdo sẽ giúp ích nếu bạn có thể nhận được đầu ra của vimgrep vào danh sách đối số (có thể được đặt bằng args), nhưng tôi không thể tìm ra chi tiết. Tôi sẽ rất vui nếu có ai đó lấy ý tưởng và cải thiện nó ... vì vậy nó ở đây.

Ý tưởng cơ bản đằng sau plugin đầu tiên (tôi đoán những người khác quá ...) là sử dụng vimgrep trước, sau đó quay vòng qua các kết quả phù hợp với :cnext và áp dụng lệnh thay thế trên mỗi dòng. Một hàm để thực hiện điều này có thể đủ nhỏ để đặt nó vào .vimrc. (Có thể bạn có thể nâng cấp một từ các nguồn của plugin?)

(Tôi cho rằng hgimenez có thể là giải pháp, nhưng có thích hợp hay không phụ thuộc vào số lượng tệp sẽ được xử lý ... nên ok bất kể.)

+0

Xin cảm ơn, nhưng arrrrgh! Có cách nào để làm điều đó mà không cần cài đặt #! * &% Plugin khác không? – Ethan

+0

@Ethan: Tôi cảm thấy cho bạn. :-) Tôi nghĩ rằng phải có một cách liên quan đến: args,: argdo,: copen hoặc bất cứ điều gì ... Tôi chỉ không sử dụng vimgrep đủ để có suy nghĩ nhiều về nó trước và dường như không thể đặt lại với nhau sửa chữa hoàn hảo cho bạn chỉ được nêu ra. Nhưng tôi vẫn đang cố gắng, vì vậy có lẽ tôi sẽ đến với một cái gì đó và chỉnh sửa. –

+0

Oh well ... Tôi thực sự không thể tìm thấy một giải pháp no-plugin sạch sẽ và đơn giản hoặc đảm bảo bản thân mình rằng không có bất kỳ. Vim-fu của tôi đang thất bại! :-(Các plugin có vẻ tốt, mặc dù, có lẽ họ sẽ có giá trị một thử ... –

4

Một cách là mở tất cả các tệp bạn muốn chạy thay thế (hoặc bất kỳ lệnh nào) và chạy :bufdo <cmd>, sẽ chạy <cmd> trên tất cả các bộ đệm mở.

7

Bạn có thể chạy vimgrep sau đó ghi lại một macro mà đi với từng ngành nghề trong đầu ra vimgrep và nào thay thế, một cái gì đó như thế này: (! Không gõ vào # comments)

:set autowrite     #automatically save the file when we change buffers 
:vimgrep /pattern/ ./**/files 
qa        #start recording macro in register a 
:s/pattern/replace/g   #replace on the current line 
:cnext       #go to next matching line 
q        #stop recording 
[email protected]       #repeat the macro 10000 times, or until stopped by 
           #an "error" such as reaching the end of the list 
:set noautowrite 

tôi đã không kiểm tra nó, do đó, nó có thể cần một chút tinh chỉnh - kiểm tra nó trên một số tập tin mà bạn không nhớ nhận được điều sai lầm đầu tiên.

Lợi thế của điều này trên sed là Vim regex mạnh hơn và bạn có thể thêm tùy chọn c vào: s để xác minh từng thay thế.

Chỉnh sửa: Tôi đã sửa đổi bài đăng gốc vì nó sai. Tôi đã sử dụng: 1vimgrep để tìm kết quả phù hợp đầu tiên trong mỗi tệp, nhưng tôi đã đọc sai tài liệu - nó chỉ tìm thấy một kết quả phù hợp trên tất cả các tệp.

+0

Thật tuyệt! Trong việc tìm kiếm một giải pháp biểu hiện duy nhất tôi không bao giờ dừng lại để xem xét một macro ... Làm cho tôi cảm thấy ngớ ngẩn bây giờ. +1. :-) –

+0

Bạn vừa lưu tôi GIỜ LÀM VIỆC, cảm ơn bạn !!! : D Tôi cần sao chép một giá trị trong tệp xml sang một phần khác của tệp, sau đó giảm giá trị nó xuống - trên 200 tệp. – Jason

45

argsargdo nên làm những gì bạn cần, ví dụ:

:args spec/javascripts/**/*.* 
:argdo %s/foo/bar/g 

Xem this page.

+0

Cảm ơn bạn! Rất thú vị :) – starikovs

+1

Whoa vimskill ++ –

+1

năm đau khổ và câu hỏi lựa chọn nghề nghiệp đã kết thúc hôm nay –

0

Tính năng này hoạt động đối với một số lượng tệp nhỏ.

vim `find. -type f `

: bufdo% s/mẫu/thay thế/gec | cập nhật

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