Witam na mojej prywatnej stronie internetowej!
[If this is all Polish to you, click here: English]
Uwaga: z oczywistych powodów nie mogę zagwarantować swojej nieomylności, choć staram się o zgodność tego, co piszę, z Prawdą. Jest również oczywiste, że nie gwarantuję takiej zgodności w przypadku komentarzy. Umieszczenie linku do strony spoza niniejszego serwisu nie musi oznaczać, że podzielam poglądy autora tej strony, a jedynie, że uważam ją za wartościową z takich czy innych powodów.
Marcin ‘mbork’ Borkowski
Some time ago I had a rather specific need. I wanted to automatically modify a bunch of files in a directory, and I wanted to automate it as much as possible – but without writing any Elisp. Don’t get me wrong, I love coding in Elisp, but in that case I wanted a solution really quickly, faster than I could possibly code it.
First of all, I knew I can record a keyboard macro which assumes that the point is on a file in Dired and performs the required edits. Here is a template for such a macro:
RET ;; dired-find-file M-< ;; beginning-of-buffer C-s ;; isearch-forward place ;; self-insert-command * 5 RET ;; isearch-exit edit ;; self-insert-command * 4 C-x C-s ;; save-buffer C-x LFD ;; dired-jump
(Note: the above output is not what you could see when typing C-x
C-k C-e
, that is, kmacro-edit-macro-repeat
. It turns out that the commands displayed on the right depend on the mode Emacs was in when pressing C-x C-k C-e
. My macro assumes that it is started in a Dired buffer but switches to editing a file. What I did was this: I first edited my macro in Dired mode, copied its contents above, then I edited it again in some other mode and copied just the commands that would be run in that mode. Then I manually replaced newline
next to RET
to what RET
really does in Isearch mode, that is, isearch-exit
.) This way the right column shows the actual commands the macro would be invoking, for the sake of clarity.)
Now this is all good – I can now press f4
with the point on a file I want to modify – but I wanted something even more streamlined. I wanted to apply my modification to every file whose name matches some regular expression. Can it be done without writing a single byte of Elisp? You bet it can! In Dired, you can easily mark a set of files based on various criteria. One of them is exactly what I need – dired-mark-files-regexp
, bound to * %
. (This seems a terrible keybinding, but it’s actually quite mnemonic. Marking commands are on the *
prefix, which is easy to remember as the normal way of marking files in Dired is with an asterisk. Then, %
reminds of C-M-%
, that is, query-replace-regexp
. And while at that, do yourself a favor and press * C-h
while in Dired to see what mark-related commands are available. For example, you can have several “types” of marks in Dired. In fact, there is even more than you can find on the *
prefix – for example searching across marked files. TIL that you can even mark all files which contain a given regex, which is insanely cool and bound to % g
– of course, * g
would be better – but g
clearly stands for grep
here.)
Now, if only I could easily move the point to the next marked file. Wait, but I can! The key M-}
(which is not easy to type, but you only need to do it once per macro in my case) is bound to dired-next-marked-file
.
This way I can record a macro which visits the file the point is on, makes the necessary changes there, saves, goes back to the Dired buffer and moves to the next marked file. A final tip is this: it might be more useful to first make the changes to the first file manually, stop right before saving and start the macro recording with the save-buffer
command. Then of course you stop the recording just before saving the next file. The rationale is that after each macro invocation you get the chance to manually inspect the changes made, and then you either accept them and just press f4
to save, move to the next file and make changes there, or adjust something in the current (unsaved) buffer and then press f4
to do the same. (You can achieve a similar result with C-x q
or C-u C-x
q
during macro recording, but it is a bit more work.)
If you are astonished that I actually advocated not coding in Elisp this time – well, Dired and Emacs keyboard macros are pretty powerful, and as you can see, can go a long way! And you can of course marry the two approaches – for example, you can create a command to make the changes you need in every of the marked files, and then record a macro which runs that command, saves the file, goes back to Dired and moves to the next marked file (or something similar). As usual with Emacs, its legendary flexibility is there for you!
That’s it for today, see you next time!