Używanie Emacsa do rekurencyjnego znajdowania i zastępowania plików tekstowych, które nie są jeszcze otwarte

Jako kontynuacjętego pytania , próbuje dowiedzieć się, jak zrobić coś takiego, co powinno być łatwe, co szczególnie powstrzymuje mnie od przyzwyczajenia się do korzystania z Emacsa i zamiast tego uruchomienia edytora, z którym już jestem zaznajomiony. Używam tego przykładu dość często przy edycji wielu plików.

W Ultraedit wykonałbym Alt + S następnie p, aby wyświetlić okno dialogowe z opcjami: Find( zawiera użycie wyrażeń regularnych w wielu wierszach), Replace with, w plikach / typach, Katalog, Dopasuj wielkość liter, Dopasuj tylko całe słowo, Wymień zmienione pliki i przeszukaj podkatalogi. Zazwyczaj najpierw użyję myszy, aby kliknąć-przeciągnąć zaznacz tekst, który chcę zastąpić.

Używając tylko samego Emacsa (w Windows XP), bez wywoływania żadnego zewnętrznego narzędzia, jak zastąpić wszystkie foo\nbar paskiem \ nbaz w plikach *.c i *.h w jakimś folderze i wszystkich folderach pod nim. Może Emacs nie jest najlepszym narzędziem do tego, ale jak można to zrobić łatwo przy użyciu minimalnej komendy?

 191
Author: Community, 2008-11-07

13 answers

  1. M-x find-name-dired: zostaniesz poproszony o podanie katalogu głównego i wzorca nazwy pliku.
  2. naciśnij t, aby "przełączyć znacznik" dla wszystkich znalezionych plików.
  3. naciśnij Q dla "zapytanie-Zastąp w plikach...": zostaniesz poproszony o wyrażenie regularne zapytania/substytucji.
  4. postępuj zgodnie z query-replace-regexp: SPACE Aby zastąpić i przejść do następnego meczu, n aby pominąć mecz itp.
  5. naciśnij C-x s, aby zapisać bufory. (Możesz następnie nacisnąć y, n lub !, aby zapisać wszystkie na raz)
 336
Author: Chris Conway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-12 12:42:28
  • M-x find-name-dired RET
    • może upłynąć trochę czasu, zanim wszystkie pliki pojawią się na liście, przewiń do dołu (M->), aż pojawi się "find finished", aby upewnić się, że wszystkie zostały załadowane
  • Naciśnij t, aby "przełączyć znak" dla wszystkich znalezionych plików
  • Naciśnij Q dla "zapytanie-Zastąp w plikach...": zostaniesz poproszony o wyrażenie regularne zapytania/substytucji.
  • postępuj tak jak w przypadku query-replace-regexp: spacja lub y, aby zastąpić i przejść do następnego dopasowania, n, aby pominąć dopasowanie, itd.
    • Typ ! aby zastąpić wszystkie wystąpienia w bieżącym pliku bez pytania, N aby pominąć wszystkie możliwe zamienniki dla reszty bieżącego pliku. (N jest tylko emacs 23+)
    • aby wykonać zastąpienie wszystkich plików bez pytania, wpisz Y.
  • wywołaj "ibuffer" (C-x C-b jeśli jest powiązany z ibuffer lub M-x ibuffer RET), aby wyświetlić listę wszystkich otwartych plików.
  • Type * u aby zaznaczyć wszystkie niezapisane pliki, type S aby zapisać wszystkie zaznaczone pliki
  • * * RET aby odznaczyć wszystkie znaki, lub wpisz D, aby zamknąć wszystkie zaznaczone pliki

Ta odpowiedź jest połączona z tej odpowiedzi , z tej strony i z moich własnych notatek. Korzystanie Z Emacs 23+.

 34
Author: Frank Henard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:33

Zazwyczaj używam innych narzędzi do wykonywania tego zadania i wydaje się, że wiele z metod wymienionych w emacswiki ' s Find and Replace Across Files entry wygląda bardzo obiecująco, ale pakiet Findr wygląda bardzo obiecująco.

Kradzież części pliku źródłowego :

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.
 12
Author: Blair Conrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-07 01:52:04

Udzielone odpowiedzi są świetne, jednak pomyślałem, że dodam nieco inne podejście.

Jest to metoda bardziej interaktywna i wymaga wgrep, rgrep i iedit. Zarówno iedit jak i wgrep muszą być zainstalowane przez MELPA lub Marmalade (używając M-x package-list-packages)

Najpierw uruchom M-x rgrep, aby znaleźć ciąg, którego szukasz.

Będziesz mógł określić typy plików / wzorzec i folder do rekurencji.

Następnie musisz uruchomić wgrep uruchom go z C-s C-p.

Wgrep będzie możesz edytować rgrep Wyniki, więc ustaw region na łańcuchu, aby pasował i zacznij iedit-mode z C-; (w zależności od terminala może być konieczne ponowne powiązanie tego)

Wszystkie zdarzenia będą edytowalne jednocześnie. C-x C-s do popełnienia wgrep. Następnie C-x s !, aby zapisać zmienione pliki.

Główną zaletą tej metody jest to, że można użyć iedit-mode, aby wyłączyć niektóre mecze M-;. Możesz również użyć wyników w rgrep, aby przejść do plików, na przykład, jeśli masz nieoczekiwany mecz.

Uważam, że jest to bardzo przydatne do edycji źródeł i zmiany nazw symboli (zmiennych, nazw funkcji itp.) w całym projekcie.

Jeśli jeszcze nie znasz/nie używasz trybu iedit to bardzo poręczne narzędzie, zdecydowanie polecam rzucić na nie okiem.

 10
Author: ocodo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-17 01:34:43

Używanie dired do rekurencji w głębokim drzewie katalogów będzie trochę wolne dla tego zadania. Możesz rozważyć użycie tags-query-replace. Oznacza to tworzenie tabeli tagów, ale i tak jest to często przydatne i szybkie.

 5
Author: Alex Coventry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-07 12:56:02

Pocisk jest naprawdę ładny: C-c p R uruchamia polecenie pocisk-replace

 5
Author: eflanigan00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 19:00:30

Źródło informacji: 1

Dla użytkowników emacs pro:

  1. wywołanie dired do listy plików w katalogu lub wywołanie find-dired, jeśli potrzebujesz wszystkich podkatalogów.
  2. zaznacz pliki, które chcesz. Możesz oznaczyć regex, wpisując 【% m】.
  3. wpisz Q, aby wywołać dired-do-query-replace-regexp.
  4. wpisz regex i zastąp łańcuch. 〔 ☛ wspólny wzorzec regex elisp〕
  5. dla każdego wystąpienia, wpisz y, aby zastąpić, n, aby pominąć. Wpisz 【Ctrl + g】 aby przerwać całość operacja.
  6. Typ ! aby zastąpić wszystkie wystąpienia w bieżącym pliku bez pytania, N pominie wszystkie możliwe zastąpienie reszty bieżącego pliku. (N to tylko emacs 23)
  7. aby wykonać zastąpienie wszystkich plików bez pytania, wpisz Y. (tylko Emacs 23)
  8. wywołaj ibuffer, aby wyświetlić listę wszystkich otwartych plików. Wpisz 【*u】, aby zaznaczyć wszystkie niezapisane pliki, wpisz S, aby zapisać wszystkie zaznaczone pliki, wpisz D, aby zamknąć je wszystkie.

Przewodnik krok po kroku dla Emacs Początkujący

Wybierz Pliki Docelowe

Uruchom Emacsa wpisując "emacs" w wierszu polecenia. (Lub kliknij dwukrotnie ikonę Emacsa, jeśli jesteś w środowisku graficznego interfejsu użytkownika)

Wybieranie plików w katalogu

Najpierw musisz wybrać pliki, które chcesz zastąpić. Użyj menu graficznego File Plik Open otwarty katalog〗. Emacs poprosi Cię o ścieżkę do katalogu. Wpisz ścieżkę katalogu, a następnie naciśnij Enter.

Teraz zostanie pokazany Lista plików, a teraz musisz zaznaczyć pliki, na których chcesz, aby regex find / replace działał. Zaznacz plik, przesuwając kursor do wybranego pliku, a następnie naciśnij m. odznacz go, naciskając u. (aby wyświetlić listę podkatalogów, przesuń kursor do katalogu i naciśnij i.zawartość podkatalogu zostanie wyświetlona na dole.) Aby oznaczyć wszystkie pliki regex, wpisz 【% m】, a następnie wpisz swój wzór regex. Na przykład, jeśli chcesz oznaczyć wszystkie pliki HTML, wpisz 【% m】 then .html$. (Można znaleźć listę polecenia oznacz w graficznym menu "zaznacz" (menu to pojawia się, gdy jesteś w trybie dired).)

Wybieranie plików w katalogu i wszystkich jego podkatalogach

Jeśli chcesz znaleźć / zastąpić pliki wewnątrz katalogu, w tym setki podkatalogów, oto metoda, aby wybrać wszystkie te pliki.

Zadzwoń do find-dired. (wywołujesz polecenie, naciskając 【Alt + x】) następnie wpisz nazwę katalogu, ⁖ / Users / mary / myfiles

Uwaga: jeśli używasz Emacsa na Uniksie nie - graficzny terminal tekstowy, a jeśli 【Alt + x】 nie działa, równoważnym pociągnięciem klawisza jest 【Esc x】.

Emacs zapyta Cię o polecenie " Uruchom find (Z args): ". Jeśli chcesz wykonać zastąpienie wszystkich plików HTML, wpisz nazwę "* html". Jeśli nie zależy ci na rodzaju pliku, ale po prostu wszystkie pliki w tym katalogu, to daj "- type f".

Teraz Oznacz pliki zgodnie z powyższym opisem.

Interactive Find / Replace

Teraz jesteś gotowy do interaktywnego znaleziska zastąp. Dla uproszczenia, powiedzmy, że po prostu chcesz zastąpić słowo "szybki" przez "super". Teraz wywołaj dired-do-query-replace-regexp. Wyświetli monit o ciąg regex i ciąg zastępczy. Wpisz "szybki", wprowadź, a następnie "super".

Teraz emacs użyje twojego wzorca i sprawdzi pliki, zatrzyma się i pokaże ci, gdy dojdzie do dopasowania. Gdy tak się stanie, emacs wyświetli monit, a Ty masz wybór dokonania zmiany lub pominięcia zmiany. Aby dokonać zmiany, wpisz y. aby pominąć, wpisz n. Jeśli po prostu chcesz, aby emacs poszedł do przodu i wprowadzić wszystkie takie zmiany w bieżącym pliku, wpisz !.

Jeśli chcesz anulować całą operację bez zapisywania wprowadzonych zmian, wpisz 【Ctrl + g】, a następnie wyjdź z Emacsa za pomocą menu 〖Plik ▸ Wyjdź z Emacsa〗.

Zapisywanie zmienionych plików

Teraz, po przejściu przez powyższą gehennę, jest jeszcze jeden krok, który musisz zrobić, a mianowicie zapisanie zmienionych plików.

Jeśli używasz Emacsa w wersji 22 lub nowszej, wywołaj ibuffer do przejdź do trybu listy buforów, a następnie wpisz 【*u】, aby zaznaczyć wszystkie niezapisane pliki, a następnie wpisz S, aby zapisać je wszystkie. (to shift-s)

Jeśli używasz Emacsa w wersji 21, możesz to zrobić: wywołaj bufory listy, następnie przesuń kursor do pliku, który chcesz zapisać i wpisz s. zaznaczy on plik do późniejszej akcji Zapisz. Wpisz u, aby odznaczyć. Po zakończeniu wpisz x, aby wykonać zapis wszystkich plików oznaczonych jako Zapisz. (w Emacsie otwarty plik nazywany jest "buforem". Lekceważ inne rzeczy tam.)

Alternatywą dla powyższych opcji, można również wywołać save-some-buffers 【Ctrl + X s】. Następnie emacs wyświetli każdy niezapisany plik i zapyta, czy chcesz go zapisać.

Uwaga: regex Emacsa nie jest taki sam jak Perla czy Pythona, ale podobny. Aby uzyskać podsumowanie i wspólne wzorce, zobacz: Emacs Regex.

 4
Author: scrapcodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-24 06:45:01

M-X Dired, i t, aby oznaczyć wszystkie pliki, i Q do zapytania zastąp tekst we wszystkich z nich. Możesz rozwinąć podkatalog używając polecenia i przed zapytaniem-replace. Dodaję informację, że jeśli podasz prefiks (control-u) do polecenia i, wyświetli monit o ARG, a argument-R rekurencyjnie rozszerzy wszystkie subdirs do bufora dired. Teraz możesz przeszukiwać każdy plik w całym katalogu.

 3
Author: Zack Murray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-22 20:59:55

Dla otwartych buforów, to jest to, co robię:

(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)))))
 2
Author: yPhil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-27 15:36:38

Inną opcją jest użycie Icicles search. Jest to inny rodzaj wyszukiwania przyrostowego, który wykorzystuje uzupełnianie danych wejściowych minibuffera w stosunku do wyników wyszukiwania. Podczas modyfikowania bieżącego wejścia zestaw pasujących trafień jest aktualizowany w buforze *Completions*.

Możesz przeszukiwać dowolną liczbę plików, buforów lub zakładek, które możesz wybrać, dopasowując wzór minibuffera (np. regexp).

Podczas odwiedzania wyszukiwania możesz zastąpić na żądanie albo cały hit lub tylko jego część, która pasuje do bieżącego wejścia minibuffera. Wymiana na żądanie oznacza, że nie jesteś pytany o każde trafienie wyszukiwania po kolei; uzyskujesz dostęp do żądanych trafień bezpośrednio, w dowolnej kolejności. Takie podejście może być bardziej skuteczne niż query-replace, jeśli masz ograniczoną liczbę zamienników do wykonania: pomijasz wyczerpujące monitowanie y/n.

Wyszukiwanie jest skończone wyszukiwanie konteksty które definiujesz-nie ograniczasz się do przeszukiwania całego tekstu w celu pliki (np. można pominąć komentarze lub poszczególne rodzaje sekcji programu). Prostym przykładem kontekstu wyszukiwania jest linia, jak w grep, ale kontekstem może być dowolny pasujący do wzorca blok tekstu, który lubisz. Zazwyczaj konteksty wyszukiwania definiujesz za pomocą wyrażenia regularnego, ale zamiast tego możesz użyć funkcji. Oprócz definiowania własnych, istnieją predefiniowane polecenia wyszukiwania sople dla różnych rodzajów kontekstów: bloki właściwości tekstu lub właściwości nakładki, rzeczy w punkcie, itd.

Możesz również sortować wyniki wyszukiwania w różnych porządkach sortowania dla Łatwiejszego Dostępu / nawigacji.

 1
Author: Drew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-24 16:55:32

find-name-dired jest OK, ale:

  • wszystkie pliki, które otrzymujesz, pasują do tego samego, pojedynczego wyrażenia regularnego.
  • find-dired jest bardziej elastyczny pod tym względem, ale jest też stworzony do korzystania z ogólnych zasad (nawet jeśli mogą być arbitralnie złożone). I oczywiście find ma swój własny, złożony język.
  • jeśli chcesz działać tylko na niektórych plikach, których nazwy zostały zebrane w buforze find(-name)-dired, musisz je zaznaczyć lub usunąć / pominąć wiersze tych, których nie chcesz działać on

Alternatywą jest użycie Dired+ polecenia, które działają na (a) zaznaczonych plikach i (b) wszystkich zaznaczonych plikach (lub wszystkich plikach, jeśli żaden nie jest zaznaczony) w zaznaczonych podkatalogach ... znaleziono rekurencyjnie . Daje to zarówno ogólność, jak i łatwą kontrolę nad wyborem pliku. Te polecenia "tu-i-poniżej" są wszystkie na klawiszu prefiksu M-+ w trybie Dired.

Na przykład, M-+ Q jest tym samym co Q --- query-replace, ale docelowymi plikami są wszystkie te zaznaczone w bieżącym katalogu i w dowolnych zaznaczonych subdirach, down, down, down...

Tak, alternatywą dla użycia takich poleceń tutaj i poniżej jest wstawianie wszystkich subdirów i ich subdirów rekurencyjnie, a następnie użycie polecenia najwyższego poziomu, takiego jak Q. Ale często może być wygodne, aby nie zawracać sobie głowy wstawionymi subdirami.

I aby to zrobić, potrzebujesz szybkiego sposobu na wstawienie wszystkich takich subdirów rekurencyjnie. Proszę. również Dired+ może pomóc. M-+ M-i wstawia rekurencyjnie wszystkie zaznaczone subdiry i ich własne. Oznacza to, że jest podobny do M-i (który wstawia oznaczone subdiry w Dired+), ale działa rekurencyjnie na subdiry.

(wszystkie takie polecenia "tu-i-poniżej" Dired+ są w menu wielokrotne > zaznaczone tutaj i poniżej .)

Możesz również wykonywać operacje Dired na zestawie plików Emacs , który jest zapisanym zestawem nazw plików znajdujących się w dowolnym miejscu. A jeśli używasz sople następnie możesz otworzyć Bufor Dired dla tylko plików w zestawie plików lub innych typach list zapisanych plików.

Możesz również zakładkę dowolny Bufor Dired, w tym taki, który tworzysz za pomocą find(-name)-dired. Daje to szybki sposób na powrót do takiego zestawu (np. zestawu projektu) później. A jeśli używasz Zakładka+ następnie zakładka Dired bufor rejestruje (a) its ls przełącza, (b) które pliki są zaznaczone, (c) które podkatalogi są wstawiane i (d) które (pod)katalogi są ukryte. Wszystko to jest przywracane po "przeskoczeniu" do zakładki. Zakładka + pozwala również dodawać do zakładek całe drzewo Dired buffer - - - przejście do zakładki przywraca wszystkie bufory w drzewie.

 1
Author: Drew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-26 20:52:34

[5]}chciałbym zaproponować jeszcze jedno świetne narzędzie, o którym jeszcze nie wspomniano, a mianowicie Helm.

Jest to świetny zamiennik dla wielu standardowych operacji Emacs obejmujących uzupełnianie, wyszukiwanie itp. W szczególności, helm-find-files pozwala na wykonywanie query replace (w tym regexp) w wielu wybranych plikach.

Wystarczy otworzyć helm-find-files, zaznaczyć odpowiednie pliki M-SPC, a następnie użyć F6 lub F7, aby uruchomić query replace lub query replace regexp w wybranym pliki.

 1
Author: Andrzej Pronobis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-25 03:35:09

Nie jest to Emacs, ale xxdiff jest wyposażony w narzędzie o nazwie xx-rename, które zrobi to dla wielu ciągów jednocześnie( np. Od Do Od Do od do), z interaktywnymi monitami, zapisuje kopie zapasowe wszystkich zmodyfikowanych plików i tworzy krótki dziennik zmian dokonanych z kontekstem. To jest to, czego zwykle używam, gdy robię duże / globalne zmiany nazw.

 -2
Author: blais,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-15 16:12:54