Tüm proje dosyalarında Vim'de arayın ve değiştirin


117

Vim'deki tüm proje dosyalarında arama ve değiştirme (onay ile) yapmanın en iyi yolunu arıyorum. "Proje dosyaları" derken, geçerli dizindeki, bazılarının açık olması gerekmeyen dosyaları kastediyorum.

Bunu yapmanın bir yolu, geçerli dizindeki tüm dosyaları açmak olabilir:

:args ./**

ve ardından tüm açık dosyalarda arama yapın ve değiştirin:

:argdo %s/Search/Replace/gce

Ancak bunu yaptığımda, Vim'in bellek kullanımı birkaç düzine MB'den 2 GB'ın üzerine çıkıyor ki bu benim için çalışmıyor.

Ayrıca EasyGrep eklentisini de yükledim, ancak neredeyse hiç çalışmıyor - ya tüm oluşumları bulamıyor ya da basılana kadar duruyor CtrlC. Şimdiye kadar bu görevi yerine getirmek için tercih ettiğim yol , arama terimi için ack- grep'i, quickfix penceresini kullanarak terimi içeren ve daha önce açılmamış herhangi bir dosyayı açın ve sonunda :bufdo %s/Search/Replace/gce.

Ya bunun için kullanılabilecek iyi, çalışan bir eklenti ya da alternatif olarak şu anda kullandığımdan daha kolay olacak bir komut / komut dizisi arıyorum.


1
@Cascabel Bu yorumu yazdığınızdan beri, bir vi.stackexchange.com sitesi var.
Flimm

Yanıtlar:


27

Greplace benim için iyi çalışıyor.

Bir de var patojen hazır sürüm üzerinde github.


8
Yükledim, :Gsearchve :Gbuffersearchvar gibi diğer komutları görüyorum ama yazdığımda :Greplacealıyorum Not an editor command: Greplace.
Ramon Tayag

belgelere göre, sözdizimi şöyledir: :Gsearch [<grep-option(s)>] [[<pattern>] [<filename(s)>]] bu nedenle, örneğin aşağıdakileri kullanarak özyinelemeli bir arama yapabilirsiniz::Gsearch -r pattern dir/
vitorbal

Greplace hakkında nefret ettiğim şey, eğer kalıp dosya adındaysa, Greplace başarısız oluyor çünkü onu dosya adında da değiştiriyorsunuz.
Daniel

2
Burada 6 yıldan sonra alışılmadık bir şey yok, ancak bu eklenti , 3+ yıl önceki bazı yeni cevaplara ( github.com/yegappan/greplace ) kıyasla ciddi şekilde güncelliğini yitirmiş durumda . Sid'in yerleşik çözümüne
bakabilirim

99

Buradaki diğer büyük seçenek, vim'i kullanmamaktır:

sed -i 's/pattern/replacement/' <files>

veya bir dosya listesi oluşturmanın bir yolu varsa, belki bunun gibi bir şey:

find . -name *.cpp | xargs sed -i 's/pattern/replacement/'
grep -rl 'pattern1' | xargs sed -i 's/pattern2/replacement/'

ve bunun gibi!


Teşekkürler! Bu eski tarz komut satırı şeylerini gerçekten öğrenmem gerekiyor. Bunun en iyi cevap olduğunu düşünüyorum. Bu normal ifadeler perl normal ifadeleri mi, vim normal ifadeleri mi yoksa başka bir tür normal ifade mi?
Eric Johnson

2
@EricJohnson: Bunlar ... sednormal ifadelerdir, bunlar aslında POSIX.2 temel düzenli ifadelerdir, ancak tam olarak değil (bu kılavuz sayfasındadır) - \nsatırsonu satırlarıyla eşleşmesine izin verirler ve diğer bazı benzer şeyler. Bu nedenle grepnormal ifadelerle hemen hemen aynıdırlar.
Cascabel

Sed komutunda -i'nin olmasının bir nedeni var mı? Man sayfası bunun bir uzantı belirtmek için olduğunu söylüyor, ancak gerçekte bir uzantı belirtmiyorsunuz.
davekaro

Tamam, aslında 's / pattern / replace /' uzantısı gibi görünüyor, sanırım şimdi anlıyorum.
davekaro

11
Mac OS X'te benim için çalışan tek sed komutu şuydu:find . -type f | LANG=C xargs sed -i '' 's/SEARCH/REPLACE/g'
ghodss

74

DÜZENLEME: Bunu gerçekleştirmek için çalıştırılacak komutların miktarını önemli ölçüde azaltmak için cfdoyerine komut kullanıncdo (çünkü her dosyada komutları çalıştırırken cdoher öğe cfdoüzerinde komut çalıştırır)

Yakın zamanda eklenen cdokomut sayesinde , grepyüklediğiniz aracı kullanarak artık bunu iki basit komutla yapabilirsiniz . Ekstra eklenti gerekmez !:

1. :grep <search term>
2. :cdo %s/<search term>/<replace term>/gc
3. (If you want to save the changes in all files) :cdo update

( cdoverilen komutu, grepkomutunuzun doldurduğu quickfix listesindeki her terim için yürütür .)

( cHer arama terimini her seferinde onaylamadan değiştirmek istiyorsanız 2. komutun sonundaki işareti kaldırın )


12
Ayrıca :cdo update, tüm dosyalardaki değişiklikleri kaydetmek için ekleyebilirsiniz .
Zhe Li

1
Ancak, geçerli arabellek değiştirildiğinde sonraki arabelleğe geçmeden önce her seferinde kaydedilmediğini uyarmak için duraklar.
09'da özgür

1
@Zhe teşekkürler, bunu cevaba ekledim; @lfree Kişisel olarak her değişikliği onaylamayı tercih ederim, ancak cikinci komutun sonunda kaldırabilirsiniz (sadece kullanın g) onay istemeden arama ve değiştirme
Sid

1
: cdo% s / search term / replace term / g yalnızca ilk geçtiği yerin yerini alır, ancak benim vim
sunxd

3
kullandığınız için update: mecbur kaldımcdo %s/<search term>/<replace term>/g | update
gabe

34

GNU alt kümesinden daha güçlü tam Perl düzenli ifadelerinden yararlanmak için bu sorunu çözmek için ack ve Perl kullanmaya karar verdim.

ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'

açıklama

ack

ack , aşağıdakilerin bir karışımı olan harika bir komut satırı aracıdır grep,find ve tam Perl düzenli ifadeler (sadece GNU alt kümesi). Saf Perl ile yazılmıştır, hızlıdır, sözdizimi vurgulamasına sahiptir, Windows üzerinde çalışır ve geleneksel komut satırı araçlarından daha programcılara dosttur. Ubuntu'ya yükleyin sudo apt-get install ack-grep.

xargs

Xargs eski bir unix komut satırı aracıdır. Standart girişten öğeleri okur ve belirtilen komutu ve ardından standart giriş için okunan öğeleri çalıştırır. Yani temelde ack tarafından oluşturulan dosyaların listesi sayfanın sonuna ekleniyor.perl -pi -E 's/pattern/replacemnt/g' komutun .

perl -pi

Perl bir programlama dilidir. -P seçeneği, Perl'in programınızın etrafında dosya adı argümanlarını yineleyen bir döngü oluşturmasına neden olur. -İ seçeneği Perl'in dosyayı yerinde düzenlemesine neden olur. Yedek oluşturmak için bunu değiştirebilirsiniz. -E seçeneği Perl'in program olarak belirtilen bir satır kodu çalıştırmasına neden olur. Bizim durumumuzda program sadece bir Perl regex ikamesidir. Perl komut satırı seçenekleri hakkında daha fazla bilgi için perldoc perlrun. Perl hakkında daha fazla bilgi için bkz. Http://www.perl.org/ .


Bu cevabı beğendim çünkü cygwin'in satır sonlarında bile işe yarıyor. Unutmayın ki değiştirilmiş satırların sonuna a \ r eklenir, ancak sed kullanıldığında her satırsonu yerine geçer ve diff'leriniz kullanılamaz hale gelir. Perl biraz daha mantıklı ve bu, arama ve değiştirme için gerçekten harika bir tek satırlık. Teşekkürler!
andrew

@andrew, senin durumunda tam olarak neyin yanlış gittiğinden emin değilim. Normal ifadelerinizde \ n yerine \ R kullanmanıza yardımcı olur mu? Perldoc.perl.org/perlrebackslash.html#Misc'deki \ R bölümüne bakın . Ayrıca perldoc.perl.org/perlre.html#Regular-Expressions'ı da deneyin . Perl son derece çapraz platformdur ve eminim karışmış satır sonları ile bitmemenizin bir yolu vardır.
Eric Johnson

Normal ifademin içinde satırsonu yok, bu programların cygwin sürümleri değiştirilen her satırın sonuna otomatik olarak \ r ekler. Perl sürümünü özellikle beğendim çünkü yalnızca eşleştiği satırları değiştirirken sed , normal ifadeyle eşleşmeseler bile tüm satırları değiştirecek .
andrew

Ya dosyanın yolu boşluklar içeriyorsa?
shengy

23

belki bunu yap:

:noautocmd vim /Search/ **/*
:set hidden
:cfirst
qa
:%s//Replace/gce
:cnf
q
1000@a
:wa

Açıklama:

  • :noautocmd vim /Search/ **/*⇒ hız uğruna autocmds ( ) 'yi tetiklemeden cwd'nin tüm alt dizinlerinde bulunan tüm dosyalarda arama kalıbı ( vimkısaltmasıdır vimgrep) :noautocmd.
  • :set hidden ⇒ değiştirilmiş arabelleklerin bir pencerede görüntülenmemesine izin ver (vimrc'nizde olabilir)
  • :cfirst ⇒ ilk arama sonucuna atla
  • qa Kayıt içine bir makro kaydını başlatmak ⇒ a
  • :%s//Replace/gce⇒ son arama modelinin tüm tekrarlarını (hala /Search/o sırada) ile değiştirinReplace :
    • aynı satırda birkaç kez (g bayrak)
    • kullanıcı onayı ile (c bayrak)
    • herhangi bir model bulunamazsa hatasız ( ebayrak)
  • :cnfvimkomutla oluşturulan listede sonraki dosyaya atla
  • q ⇒ makro kaydetmeyi durdur
  • 1000@a ⇒ kayıtta 1000 kez saklanan makroyu oynat
  • :wa ⇒ tüm değiştirilmiş arabellekleri kaydedin

* DÜZENLE * Vim 8 yolu:

:cfdoQuickfix listesindeki tüm dosyalarda yinelendiği için, Vim 8'den başlayarak bunu yapmanın daha iyi bir yolu vardır :

:noautocmd vim /Search/ **/*
:set hidden
:cfdo %s//Replace/gce
:wa

bunu biz ölümlüler için biraz daha ileri götürmek isteyebilirsiniz. Her seferinde bu "sekansı" yapmanız gerekip gerekmediği bana açık değil. Bunu paslı eski Delphi 5'imi kullanarak daha hızlı yapıyorum, bu yüzden kesinlikle bir şeyler kaçırıyor olmalıyım.
Lieven Keersmaekers

1
@Lieven: Haklısın, bu yorumsuz biraz belirsiz. Bazı açıklamalar geliştireceğim.
Benoit

+1 ama vimbeni birçok şey için kazanmış olsa da , bununla PowerGrep'e bağlı kalacağımı düşünüyorum.
Lieven Keersmaekers

Cevabınız ve tüm komutların açıklaması için teşekkürler, gerçekten minnettarım. Diğer yanıtı kabul ediyorum çünkü bunun için bir eklenti kullanmayı tercih ediyorum.
psyho

Soruyu soran birinin seviyesi ile bu cevabı anlamak için gereken seviye arasındaki eşitsizlik göz önüne alındığında, bu daha fazla kafa karışıklığına neden olduğu için bunu işaretledim.
Lloyd Moore

22

:argsBir kabuk komutundan doldurun

Dosyaları bir kabuk komutu aracılığıyla sağlamak (bazı işletim sistemlerinde 1 )) mümkündür :args.

Örneğin, ack 2 yüklediyseniz,

:args `ack -l pattern`

ack'ten 'desen' içeren dosyaların bir listesini döndürmesini ve bunları argüman listesine koymasını isteyecektir.

Veya sade ol 'grep ile sanırım şöyle olurdu:

:args `grep -lr pattern .`  


Daha sonra :argdoOP'de açıklandığı gibi kullanabilirsiniz :

:argdo %s/pattern/replacement/gce


Doldur :argsQuickFix listeden

Ayrıca kontrol nelstrom cevabını akım QuickFix listeden Arglist doldurur basit bir kullanıcı tanımlı komutu açıklayan ilgili soruya. Bu, çıktısı quickfix listesinde ( :vimgrep, :Ack3 , :Ggrep4 ) biten birçok komut ve eklentiyle harika çalışır .

Proje çapında bir arama gerçekleştirme sırası daha sonra aşağıdakilerle yapılabilir:

:vimgrep /pattern/ **/*
:Qargs 
:argdo %s/findme/replacement/gc

:Qargsquickfix listesinden arglisti dolduran kullanıcı tanımlı komuta yapılan çağrı nerede .

Sonraki tartışmada da bağlantılar bulacaksınız bu iş akışını 2 veya 3 komuta indiren basit eklentilere .

Bağlantılar

  1. : h {arglist} - vimdoc.sourceforge.net/htmldoc/editing.html#{arglist}
  2. ack - betterthangrep.com/
  3. ack.vim - github.com/mileszs/ack.vim
  4. kaçak - github.com/tpope/vim-fugitive

1
argdo, yazma sorunu olan ilk dosyadan sonra duruyor
frankster


5

Eğer dış bağımlılık tanıtılması sakıncası yoksa, ben bir eklenti demlenmiş var ctrlsf.vim (bağlıdır ack veya ag işi yapmak için).

Ack / ag'den arama sonucunu biçimlendirebilir ve görüntüleyebilir ve sonuç tamponundaki değişikliklerinizi diskteki gerçek dosyalarla senkronize edebilir.

Belki demoyu takip etmek daha fazlasını açıklar

ctrlsf_edit_demo


3
1. :grep <search term> (or whatever you use to populate the quickfix window)
2. :cfdo %s/<search term>/<replace term>/g | update

Adım 1, hızlı düzeltme listesini istediğiniz öğelerle doldurur. Bu durumda, değiştirmek istediğiniz arama terimleriyle yayılır grep.

cfdoquickfix listesindeki her dosyada aşağıdaki komutu çalıştırır. Tip :help cfdodetaylar için.

s/<search term>/<replace term>/gher terimi değiştirir. /gdosyadaki her geçtiği yerin değiştirilmesi anlamına gelir.

| update her değiştirmeden sonra dosyayı kaydeder.

Bu cevaba ve yorumlarına dayanarak bunu bir araya getirdim , ancak hepsi tek bir yerde olduğu için kendi cevabını hak ettiğini hissettim.


Benim için NeoVim'de, yukarıdaki 2. satırda küçük bir değişiklik yapılması gerekiyordu: 2. :cfdo %s/<search term>/<replace term>/g | updateBu olmadan %, modelin yalnızca ilk oluşumu değiştirilir.
Kareem Ergawy

Teşekkürler Kareem. %sNormal vim üzerinde de çalıştığı için cevabı güncelledim .
Kyle Heironimus

0

Temel olarak, tek bir komutta ve daha da önemlisi vim'in kendi içinde değiştirmeyi istedim

@Jefromi'nin cevabına dayanarak, .vimrc dosyamda bunun gibi ayarladığım bir klavye kısayolu oluşturdum

nmap <leader>r :!grep -r -l  * \| xargs sed -i -e 's///g'

şimdi vim'den, bir lider darbesiyle + r, aşağıdaki gibi düzenlediğim vim'e yüklenmiş komutu alıyorum,

:!grep -r -l <find> <file pattern> | xargs sed -i -e 's/<find>/<replace>/g'

Bu nedenle, değiştirmeyi tek bir komutla ve daha da önemlisi vim'in kendi içinde yapıyorum


ve aslında grep yerine ag kullanıyorum
deepak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.