Zaten açık olmayan metin dosyalarını yinelemeli olarak bulmak ve değiştirmek için Emacs kullanma


212

Bu sorunun bir takibi olarak, kolay olması gereken, özellikle de Emacs'ı kullanmaya daha alışmamı ve bunun yerine zaten aşina olduğum editörü başlatmak için böyle bir şeyi nasıl yapacağımı bulmaya çalışıyor. Buradaki örneği sık sık birden çok dosyayı düzenlemede kullanıyorum.

Ultraedit'te Alt + s sonra p seçenekleri ile bir iletişim kutusu görüntülemek için yapardım: Bul (birden çok satırda normal ifadelerin kullanılmasını içerir), Değiştir, Dosyalarda / Türlerinde, Dizin, Eşleşme Durumu, Yalnızca Tam Kelimeyle Eşleştir, Liste Değişen Dosyalar ve Arama Alt Dizinleri. Genellikle değiştirmek istediğim metni seçmek için fareyi tıklatarak sürüklerim.

Herhangi bir harici yardımcı programı çağırmadan yalnızca Emacs'ın kendisini (Windows XP'de) kullanarak, tüm foo \ nbar'ı bar \ nbaz in *.cve *.hbazı klasördeki dosyalar ve altındaki tüm klasörler ile nasıl değiştirebilirim . Belki Emacs bunu yapmak için en iyi araç değildir, ancak minimal bir komutla nasıl kolayca yapılabilir?

Yanıtlar:


370
  1. M-x find-name-dired: bir kök dizin ve bir dosya adı kalıbı istenir.
  2. tBulunan tüm dosyalar için "işareti değiştir" seçeneğine basın .
  3. Q"Dosyalarda Sorgu Değiştir ..." için basın : sizden sorgu / ikame normal ifadeleri istenir.
  4. Şu şekilde ilerleyin query-replace-regexp: SPACEdeğiştirmek ve bir sonraki maça ngeçmek, bir maçı atlamak vb.
  5. C-x sTamponları kaydetmek için tuşuna basın . (Daha sonra tümünü bir kerede kaydetmek için y, nveya tuşuna basabilirsiniz !)

10
Hayır, özyinelemeli. Özyinelemesiz sürüm dired modunda% m olacaktır.
Chris Conway

5
Belki GNU find değil C: \ WINDOWS \ system32 \ find.exe'yi çağırdığınız için.
Jazz

6
Steen, Chris: Muhtemelen tam olarak ne istediğinizi değil, ancak 'Cx s' (bazı kaydetme tamponları) kullanabilirsiniz, değiştirilen her dosya için sizi uyaracaktır, bu yüzden sadece 'y' tuşuna birkaç kez basmanız gerekir.
danielpoe

48
C-x s !tüm dosyaları bir kerede kaydetmek için.
cYrus

10
M-,aramaya ve değiştirmeye devam etmek için (örneğin, dosya diskte değiştiyse "dosyayı geri döndür" isteminden sonra).
tfischbach

37
  • M-x find-name-dired RET
    • tüm dosyaların listede görünmesi biraz zaman alabilir, hepsinin yüklendiğinden emin olmak için M->" find finished" görünene kadar aşağıya ( ) ilerleyin
  • tBulunan tüm dosyalar için "işareti değiştir" düğmesine basın
  • Q"Dosyalarda Sorgu Değiştir ..." için basın : sizden sorgu / ikame normal ifadeleri istenir.
  • Query-replace-regexp: SPACE ile devam edin veya bir ysonraki eşleşmeyi değiştirmek ve bir sonraki eşlemeye geçmek, n ​​bir eşleşmeyi atlamak vb.
    • Tür! geçerli dosyadaki tüm tekrarlamaları sormadan Ndeğiştirmek, geçerli dosyanın geri kalanının olası tüm değiştirilmesini atlamak. ( Nsadece emacs 23+)
    • Değiştirmeyi başka dosyalara sormadan yapmak için yazın Y.
  • C-x C-bAçık olan M-x ibuffer RETtüm dosyaları listelemek için “ibuffer” çağırın ( ibuffer'a bağlıysa veya ).
  • Tip * ukaydedilmemiş tüm dosyaları işaretlemek için, yazın Stüm işaretli dosyaları kaydetmek için
  • * * RETTüm işaretlerin işaretini kaldırmak veya Dişaretli tüm dosyaları kapatmak için yazın

Bu cevap bu cevaptan , bu siteden ve kendi notlarımdan birleştirildi. Emacs 23+ kullanma.


3
ibufferC-x C-bvarsayılan olarak bağlı değildir .
phils

2
Eh şahsen insanların tavsiye yok bağlamak C-x C-biçin ibufferbağlayıcı varsayılan dışında çok daha iyi, çünkü. Sadece (global-set-key (kbd "C-x C-b") 'ibuffer).emacs dosyanıza ekleyin . Başarısız olursa, M-x ibuffer RETyukarıdaki talimatlarda kullanın .
phils

tamam. Bence emacs başlangıç
setim var

1
Dosya bla-bla-blasalt okunur olarak ziyaret edilir ve arama durur. Nasıl önlenir / görmezden gelinir ve değiştirilmeye devam edilir? Teşekkürler.
Felipe

3
Neden ibufferne zaman yapabilirsiniz C-x s( save-some-buffers) ve tip !? Rütbe olmak istemiyorum, sadece merak ediyorum. PS artı tanımlamak için !, Nve Y.
d12frosted

17

Verilen cevaplar harika, ancak biraz farklı bir yaklaşım ekleyeceğimi düşündüm.

Bir daha interaktif yöntem, ve gerektirir wgrep, rgrepve iedit. Hem ieditve wgrepMELPA veya marmelat (kullanarak ile yüklenmiş olması gerekir M-x package-list-packages)

İlk M-x rgreparadığınız dizeyi bulmak için çalıştırın .

Dosya türlerini / desenini ve geri alınacak klasörü belirtebilirsiniz.

Sonra çalıştırmak wgrepiçin ile çalıştırmak gerekir C-s C-p.

Wgrep Düzenlemek sağlayacak rgrepsonuçlara yüzden maç ve başlatmak için ipe bir bölge set iedit-modeile C-;(eğer yeniden bağlamak bu gerekebileceği için terminale bağlı olarak)

Tüm olaylar bir kerede düzenlenebilir. C-x C-staahhüt etmek wgrep. Sonra C-x s !değiştirilen dosyaları kaydetmek için.

Bu yöntemin ana yararı, iedit-modebelirli eşleşmeleri kapatmak için kullanabilmenizdir M-;. Sonuçları rgrepdosyalara atlamak için de kullanabilirsiniz, örneğin beklenmedik bir eşleşmeniz varsa.

Bir projede kaynak düzenlemeleri yapmak ve sembolleri (değişkenler, işlev adları vb.) Yeniden adlandırmak için çok yararlı buluyorum.

İedit modunu zaten bilmiyorsanız / kullanmıyorsanız çok kullanışlı bir araçtır, kesinlikle bir göz atmanızı tavsiye ederim.


Bu teknik iedit kullanmadan bile oldukça güçlüdür. Nasıl grep (lgrep / rgrep ile kolay) bilmek nasıl toplu arama-değiştirme bilmek için dönüşür!
NeilenMarais

Rgrep / wgrep / makroları birleştirmek harika.
ocodo

2
Başlatmak için keybinding wgrepolduğunu C-c C-pBtw.
techniao

15

Mermi gerçekten güzel: Cc pr mermi değiştirme yerine çalışır


13

Bu görevi gerçekleştirmek için genellikle diğer araçları kullanıyorum ve EmacsWiki'nin Dosyalarda Bul ve Değiştir giriş kabuğunda belirtilen birçok yaklaşım gibi görünüyor , ancak Findr Paketi çok umut verici görünüyor.

Kaynak dosyanın bir kısmını çalmak :

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.

find.el kullanarak java ve hxx uzantılı tüm dosyalarda "Koleksiyon" dizesini bulmayı nasıl deneyebilirim?
swdev

@swdev: Mx findr-query-replace RET Tahsil RET <değiştirme> RET. * \. java RET <aramaya başlanacak dizin> RET
ShreevatsaR

Bu yaklaşımı seviyorum (doğrudan yaklaşıma dahil olan tüm geçişleri önler). Bunu mermi ile birleştirmek için bazı kolaylık işlevlerini kullanıyorum (proje kökü keşfetme) ve şu noktayı değiştiriyorum: gist.github.com/anonymous/055a9d62f9fc824153599724b8f44d57
Att Righ

6

Bilgi kaynağı: 1

Emacs pro kullanıcıları için:

  1. Dir dizinindeki dosyaları listelemek için dired çağrısını yapın veya tüm alt dizinlere ihtiyacınız varsa find-dired çağırın.
  2. İstediğiniz dosyaları işaretleyin. 【% M】 yazarak normal ifade ile işaretleyebilirsiniz.
  3. Dired-do-query-replace-regexp'yi çağırmak için Q yazın.
  4. Bulgu ifadenizi yazın ve dizeyi değiştirin. El ☛ ortak elisp normal ifade〕
  5. Her bir olay için, değiştirmek için y, atlamak için n yazın. Tüm işlemi iptal etmek için 【Ctrl + g】 yazın.
  6. Tür! geçerli dosyadaki tüm tekrarlamaları sormadan değiştirmek için N, geçerli dosyanın geri kalanı için olası tüm değiştirmeleri atlamak için. (N yalnızca emacs 23'tür)
  7. Değiştirmeyi daha fazla sormadan tüm dosyalarda yapmak için Y yazın (yalnızca Emacs 23)
  8. Tüm açık dosyaları listelemek için ibuffer'ı arayın. Kaydedilmemiş tüm dosyaları işaretlemek için 【* ​​u】 yazın, işaretli tüm dosyaları kaydetmek için S yazın, tümünü kapatmak için D yazın.

Emacs Yeni Başlayanlar için Adım Adım Kılavuz

Hedef Dosyaları Seçin

Komut satırı arabirim istemine "emacs" yazarak emacs'i başlatın. (Veya bir Grafik Kullanıcı Arayüzü ortamındaysanız Emacs simgesine çift tıklayın)

Bir Dizindeki Dosyaları Seçme

Öncelikle, yerine koymak istediğiniz dosyaları seçmeniz gerekir. Grafik menüsünü kullanın 〖Dosya ▸ Dizin Aç〗. Emacs sizden bir dizin yolu isteyecektir. Dizin yolunu yazın ve ardından Enter tuşuna basın.

Şimdi, dosyaların listesini göstereceksiniz ve şimdi normal ifade bul / değiştir işlevinin çalışmasını istediğiniz dosyaları işaretlemeniz gerekiyor. İmleci istediğiniz dosyaya taşıyarak bir dosyayı işaretlersiniz, sonra m tuşuna basın. U tuşuna basarak işareti kaldırın. (Alt dizinleri listelemek için imlecinizi dizine taşıyın ve i tuşuna basın. Alt dizinin içeriği en altta listelenir.) Tüm dosyaları normal ifadeyle işaretlemek için 【% m】 yazın ve ardından normal ifade deseninizi yazın. Örneğin, tüm HTML dosyalarını işaretlemek istiyorsanız, 【% m】 ve ardından .html $ yazın. (İşaret komutlarının bir listesini “Mark” grafik menüsünde bulabilirsiniz (bu menü yönlendirme modunda olduğunuzda görünür).)

Bir Dizindeki Dosyaları ve Tüm Alt Dizinlerini Seçme

Yüzlerce alt dizin de dahil olmak üzere bir dizinin içindeki dosyaları bulmak / değiştirmek istiyorsanız, işte tüm bu dosyaları seçmek için bir yöntem.

Find-dired'i arayın. (【Alt + x】 tuşlarına basarak bir komutu çağırırsınız) Ardından, bir dizin adı yazın, ⁖ / Kullanıcılar / mary / dosyalarım

Not: unix grafik olmayan bir metin terminalinde emac kullanıyorsanız ve 【Alt + x】 çalışmazsa, eşdeğer tuş vuruşu 【Esc x】 olur.

Emacs sizden “Run find (args ile):” komutunu soracaktır. Değiştirme işlemini tüm HTML dosyalarında yapmanız gerekiyorsa, -name "* html" yazın. Ne tür bir dosya ile ilgilenmiyorsanız, sadece bu dizin altındaki tüm dosyalar için “-type f” verin.

Şimdi dosyaları yukarıda açıklandığı gibi işaretleyin.

Etkileşimli Bul / Değiştir

Şimdi, etkileşimli bulma yerine geçmeye hazırsınız. Basitlik açısından, "hızlı" kelimesini "süper" ile değiştirmek istediğinizi varsayalım. Şimdi dired-do-query-replace-regexp'yi çağırın. Sizden regex dizesini ve yeni dizeyi girmeniz istenir. “Quick” yazın, girin ve ardından “super” yazın.

Şimdi, emacs kalıbınızı kullanacak ve dosyaları kontrol edecek ve bir eşleşme gerçekleştiğinde durup size gösterecektir. Bu olduğunda, emacs sizi uyarır ve değişikliği yapma veya değişikliği atlama seçeneğiniz vardır. Değişikliği yapmak için y yazın. Atlamak için n yazın. Emacs'ın devam etmesini ve geçerli dosyada bu tür değişiklikleri yapmasını istiyorsanız! Yazın.

Yaptığınız değişiklikleri kaydetmeden tüm işlemi iptal etmek istiyorsanız, 【Ctrl + g】 yazın, ardından 〖Dosya ▸ Emacs'dan Çık〗 menüsünü kullanarak emacs'ten çıkın.

Değiştirilen Dosyaları Kaydetme

Şimdi, yukarıdaki sorundan geçtikten sonra, yapmanız gereken bir adım daha var ve bu, değiştirilen dosyaları kaydediyor.

Emacs sürüm 22 veya daha yenisini kullanıyorsanız, arabellek listesi moduna geçmek için ibuffer'ı arayın, ardından kaydedilmemiş tüm dosyaları işaretlemek için 【* ​​u】 yazın, ardından hepsini kaydetmek için S yazın. (bu vardiyalar)

Bir emacs sürüm 21 kullanıyorsanız, bunu yapabilirsiniz: liste arabelleklerini çağırın, ardından imleci kaydetmek istediğiniz dosyaya taşıyın ve s yazın. Daha sonra kaydetme işlemi için dosyayı işaretler. İşaretini kaldırmak için u yazın. İşiniz bittiğinde, kaydetmek üzere işaretlenmiş tüm dosyaların kaydedilmesini yürütmek için x yazın. (emac'larda, açılan dosyaya “tampon” denir. Orada başka şeyleri dikkate almayın.)

Yukarıdaki seçeneklere alternatif olarak, save-some-buffers 【Ctrl + xs 】'yi de çağırabilirsiniz. Ardından emac'lar kaydedilmemiş her dosyayı görüntüler ve kaydedilmesini isteyip istemediğinizi sorar.

Not: emacs'ın normal ifadesi Perl veya Python'larla aynı değil, benzerdir. Özet ve yaygın kalıplar için bkz. Emacs Regex.


2
Bu cevap, umarım en çok oy alan cevaptan daha acemi bir dost olmalıdır. Bu arada beni bağlantı yerine her şeyi koymam için motive ettiğin için teşekkürler.
Prashant Sharma

Cevap ilk satır olarak source: ile başlar. Kopya yapıştırma için gerekçe: bazen bloglara harici bağlantı modası geçmiş olur ve daha sonra cevap işe yaramaz hale gelir. Ve böylece wiki meta tarafından önerildiği gibi. Her şeyi kopyalamaya karar verdim.
Prashant Sharma

5

Derin bir dizin ağacını geri almak için dired kullanmak bu görev için biraz yavaş olacak. Tags-query-replace kullanmayı düşünebilirsiniz . Bu, bir etiket tablosu oluşturmak için bombardımanı yapmak anlamına gelir, ancak bu yine de genellikle yararlıdır ve hızlıdır.


Sadece 14.000'den fazla dosya içeren bir dizinde denedim. Emacs'ta açılır pencerede birkaç saniye sürdü. Kesinlikle yavaş değil (artık).
Berend de Boer

3

Açık tamponlar için yaptığım şey bu:

(defun px-query-replace-in-open-buffers (arg1 arg2)
  "query-replace in all open files"
  (interactive "sRegexp:\nsReplace with:")
  (mapcar
   (lambda (x)
     (find-file x)
     (save-excursion
       (goto-char (point-min))
       (query-replace-regexp arg1 arg2)))
   (delq
    nil
    (mapcar
     (lambda (x)
       (buffer-file-name x))
     (buffer-list)))))

3

M-X Diredve t ile tüm dosyaları işaretleyin ve Qiçindeki tüm metinlerin yerini değiştirin. iSorgu değiştirmeden önceki komutu kullanarak bir alt dizini genişletebilirsiniz . Eklediğim anahtar bilgiler, i komutuna bir önek (kontrol-u) verirseniz, arg için istemde bulunacağı ve -R bağımsız değişkeninin tüm arabellek subdirs içine genişleyeceğidir dired. Böylece artık tüm bir dizindeki her dosyayı sorgulayabilir ve arayabilirsiniz.


2

Başka bir seçenek, buz sarkıtları aramasını kullanmaktır . Bu, minibuffer girişinizin arama isabetlerine karşı tamamlanmasını kullanan farklı bir artımlı arama türüdür. Geçerli girişinizi değiştirdikçe, eşleşen isabet kümesi arabellekte güncellenir *Completions*.

Minibuffer desen (ör. Normal ifade) eşleşmesini kullanarak seçebileceğiniz herhangi bir sayıda dosya, arabellek veya yer işareti konmuş konumu arayabilirsiniz.

Ziyaret, bir arama yapabilirsiniz isabet değiştirmek talep üzerine tüm hit veya geçerli minibuffer girişini maçları bunun sadece bir parçası ya. Talep üzerine değiştirme, sırayla her bir arama isabeti hakkında sorgulanmadığınız anlamına gelir; istediğiniz isabetlere istediğiniz sırayla doğrudan erişirsiniz. Yapmanız gereken sınırlı sayıda yeriniz varsa, bu yaklaşım sorgu değiştirme yerine daha etkili olabilir: kapsamlı bilgi y/nistemini atlarsınız.

Arama, tanımladığınız arama bağlamları üzerindedir - hedef dosyalardaki metnin tümünü aramakla sınırlı değilsiniz (ör. Yorumları veya belirli program bölümlerini atlayabilirsiniz). Arama bağlamının basit bir örneği, olduğu gibi bir satırdır grep, ancak bağlam, istediğiniz desenle eşleşen herhangi bir metin bloğu olabilir. Genellikle arama bağlamlarını bir regexp kullanarak tanımlarsınız, bunun yerine bir işlev kullanabilirsiniz. Kendinizi tanımlamanın yanı sıra, farklı bağlam türleri için önceden tanımlanmış buz sarkıtları arama komutları vardır: metin özelliklerinin veya yer paylaşımı özelliklerinin blokları, noktadaki şeyler, vb.

Daha kolay erişim / gezinme için arama sonuçlarını çeşitli sıralama düzenlerinde de sıralayabilirsiniz .


2

find-name-dired tamam, ancak:

  • Aldığınız tüm dosyalar aynı tek regexp ile eşleşir.
  • find-diredbu konuda daha esnektir, ancak genel kuralları kullanmak için de yapılır (keyfi olarak karmaşık olsalar bile). Ve tabi kifind kendi, karmaşık bir dili var.
  • daha sonra adları find(-name)-diredarabellekte toplanan dosyaların yalnızca bir kısmı üzerinde işlem yapmak istiyorsanız , bunları işaretlemeniz veya üzerinde işlem yapmak istemediğiniz dosyaların satırlarını silmeniz / atlamanız gerekir.

Bir alternatif kullanmaktır , (a) işaretli dosyalar üzerinde etkili olan Dired + komutlarını ve (b)işaretli alt dizinlerdekitüm işaretli dosyalar (veya işaretli değilse tüm dosyalar)...yinelemeli olarakbulunankomutları. Bu, dosya seçimi üzerinde hem genel hem de kolay kontrol sağlar. Bu "burada ve aşağıda" komutlarının tümüM-+Dired modundaönektuşundadır.

Örneğin, --- query-replace ile M-+ Qaynıdır Q, ancak hedef dosyalar geçerli dizinde ve işaretli alt dizinlerde, aşağı, aşağı, aşağı ...

Evet, komutlara-ve-aşağıya burada böyle kullanmaya alternatif olmaktır eklemek yinelemeli, tüm subdirs ve bunların subdirs ve sonra gibi bir üst düzey komutunu kullanınQ . Ancak, eklenen alt dizinlerle uğraşmamak genellikle uygun olabilir.

Ve bunu yapmak için, yine de bu tür tüm alt dizinleri özyineli olarak eklemek için hızlı bir yola ihtiyacınız var . Burada da Dired + yardımcı olabilir. M-+ M-iişaretli tüm alt dizinleri ve kendi işaretli alt dizinlerini özyinelemeli olarak ekler. Yani, M-i(işaretli alt dizinleri Dired + ' da ekleyen ) gibidir, ancak alt dizinlerde özyinelemeli olarak çalışır.

(Tüm "burada ve aşağıda" Dired + komutları Çoklu > Burada ve Aşağıda İşaretlendi menüsünde bulunur .)

Bir Emacs dosya kümesinde Dired işlemlerini de gerçekleştirebilirsiniz , herhangi bir yerde bulunan dosyaların kaydedilmiş bir ad kümesi olan . Ve buz sarkıtları kullanıyorsanız o zaman bir dired bir dosya seti veya kayıtlı dosya listeleri diğer türleri sadece dosyalar için tampon açabilirsiniz.

Ayrıca , kullanarak oluşturduğunuz herhangi bir Dired arabelleğe yer işareti koyabilirsiniz find(-name)-dired. Bu, daha sonra böyle bir sete (örneğin bir proje seti) geri dönmenin hızlı bir yolunu sunar. Yer İşareti + kullanırsanız, bir Dired buffer'ı yer imlerine eklediğinizde (a) lsanahtarları, (b) hangi dosyaların işaretlendiği, (c) hangi alt dizinlerin eklendiği ve (d) hangi (alt) dizinlerin gizlendiği kaydedilir. Yer işaretine "atladığınızda" tüm bunlar geri yüklenir. Yer İşareti + aynı zamanda tüm Dired arabelleklerini yer imlerine eklemenizi sağlar --- yer işaretine atlamak ağaçtaki tüm arabellekleri geri yükler.


Kim: Bu cevabı neden indirdiğinizi açıklamak ister misiniz?
Drew

1

Henüz belirtilmemiş harika bir araç, yani Helm önermek istiyorum .

Tamamlama, arama vb. İçeren birçok standart Emacs işlemi için mükemmel bir alternatiftir. Özellikle, helm-find-filesbirden fazla seçilen dosyada sorgu değiştirme (regexp dahil) yapılmasına izin verir.

Sadece açık helm-find-files, ile ilgili dosyaları işaretlemek M-SPCve sonra kullanmak F6veya F7değiştirmek sorgu çalıştırmak için ya da seçilen dosyaları regexp'in yerini sorgusu.


Can helm-find-filesyerine regexp tarafından işaretlemek M-SPC?
Nordlöw

-2

Emacs değil, ancak xxdiff, xx-rename adında bir araçla birlikte gelir; bu, bir kerede birden fazla dize için (örn. bağlam ile yapılan değişikliklerin günlüğü. Büyük / global yeniden adlandırmalar yaptığımda bunu kullanmaya eğilimliyim.

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.