Emacs 26.1, Windows 10, Dired+
How to append contents of multiple files in one folder into one file?
Here's a function that appends the contents of each file under DIR and writes the results into a result.txt file in the same directory.
(defun append-file-contents (dir)
(interactive "DDirectory: ")
(let (contents
(default-directory dir)
(files (directory-files dir nil "^\\([^#.~]\\)")))
(dolist (file files)
(when (file-regular-p file)
(push (with-temp-buffer
(insert-file-contents file)
(buffer-string))
contents)))
(write-region (mapconcat #'identity contents "\n")
nil (concat dir "result.txt"))))
One way to get it done is Shell Commands in Dired, together with cat
:
C-x d
m
Run a shell command by hitting !
and typing the command: cat ? >> /path/to/accumulate-file.txt
The ?
surrounded with whitespaces means running the shell command once for each marked files,
with ?
being replaced by the file name.
cat
, it seems I'm wrong from OP's comment. I am trying to do it in elisp way.
Commented
Feb 8, 2019 at 11:34
cat
as you mentioned in other comment, then I don't understand why this error. Is there any other app "lock" the files? Does cat
work in Git Bash?
Commented
Feb 8, 2019 at 14:04
Open the buffer where you want to insert the files and put point where you want the text to be inserted.
Find the directory with the files, i.e., C-x C-f. The directory is shown in a dired buffer.
Mark the files with m.
a. You can also mark with % m if you want to select the files by a regular expression.
b. You can also use % g if you want to mark files containing matches for a given regular expression.
The basic lisp code that provides you with the list of marked files is:
(dired-get-marked-files)
The files have the same order as in the dired buffer. You can also sort in other ways with cl-sort
.
Insert files from the list into your target buffer. Therefore run the following lisp code with the dired buffer current:
(dolist (fn (dired-get-marked-files)) (with-current-buffer "target-buffer-name" (insert-file fn)))
Note:
a. You have to replace "target-buffer-name"
by the name of your target buffer. Often that is the file name of your target file.
b. For this command to work the buffer with name "target-buffer-name"
must already exists.
c. If you want to create a new buffer use (get-buffer-create "target-buffer-name")
instead.
You can run the elisp expressions in the current buffer easily with the key sequence M-:. You just input the elisp expression in the minibuffer and run it by pressing the RET button.
insert-file
says: Don’t call it from programs! Use ‘insert-file-contents’ instead.
, so maybe insert-file-contents
is better?
Commented
Feb 8, 2019 at 12:11
(dired-get-marked-files)
seem more intuitive to me to get the file lists, and it returns them as in the buffer top-down.
Commented
Feb 8, 2019 at 12:18
(dired-map-over-marks ...)
by (dired-get-marked-files)
. I know about insert-file-contents
and opted for insert-files
because it works and it is shorter. At this point one just needs the job to be done.
dired-get-marked-files
is from dired+.el
which is not necessarily installed. Therefore I will add my original solution again.
dired-mode
for that. Just use M-!
if that works for you. The solution I offered is elisp only and works independently of the OS.
...And then there is the Eshell-way. It uses Elisp under the hood when needed. Therefore it is OS-independent:
Open an Eshell via M-x eshell
.
Change directory in the Eshell to the one you want with cd YourDirectoryPath
.
Concatenate all files you want in Eshell with cat Pattern*Of*Source*Files > targetFile
.
Note, emacs -Q
uses Elisp for all above steps under Ubuntu (WSL):
~ $ which cd
eshell/cd is a compiled Lisp function in ‘em-dirs.el’.
~ $ which cat
eshell/cat is a compiled Lisp function in em-unix.el.
For completeness, as sometimes the crudest of methods is the most appropriate...
C-x C-f
(find-file
)C-x h
(mark-whole-buffer
)M-w
(kill-ring-save
)C-x C-f
(find-file
)M->
(end-of-buffer
)C-y
(yank
)At this point, you could save over the original first file using C-x C-s
(save-file
) or save a copy using C-x C-w
(write-file
). Repeat this as needed for all the files.
Open file1.txt
using C-x C-f
(find-file
). Press M-!
to execute shell-command
. The command you want to execute is copy
:
copy /b file1.txt + file2.txt + file2.txt file1.txt
Reload the buffer using M-x revert-buffer
to see that indeed the files were appended. Beware! The copy
command will overwrite file1.txt
.
If you don't have file1.txt
open, then the default-directory
will not be for the correct folder. You would need to either issue cd
first to change the default directory for the current buffer or use absolute paths.
cat
. If you have Gitbash installed, though, then you do and it's likely on the path. You could use type
, though. stackoverflow.com/questions/60244/…
Commented
Feb 8, 2019 at 13:48