关于elisp:Emacs中的惯用文本批处理?

Idiomatic batch processing of text in Emacs?

在Python中,您可能会做类似

1
2
3
4
5
6
7
fout = open('out','w')
fin = open('in')
for line in fin:
    fout.write(process(line)+"\
")
fin.close()
fout.close()

(我认为在许多其他语言中也是如此)。
在Emacs Lisp中,您会做类似的事情吗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(find-file 'out')
(setq fout (current-buffer)
(find-file 'in')
(setq fin (current-buffer)
(while moreLines
 (setq begin (point))
 (move-end-of-line 1)
 (setq line (buffer-substring-no-properties begin (point))
 ;; maybe
 (print (process line) fout)
 ;; or
 (save-excursion
  (set-buffer fout)
  (insert (process line)))
 (setq moreLines (= 0 (forward-line 1))))
(kill-buffer fin)
(kill-buffer fout)

我从Emacs Lisp那里得到了启发(和代码):逐行处理文件。 还是我应该尝试完全不同的东西? 以及如何从打印语句中删除""


如果您实际上要对stdin进行批处理并将结果发送到stdout,则可以对Emacs使用--script命令行选项,这将使您能够编写从stdin读取并写入stderr

这是一个类似于cat的示例程序,但它会反转每一行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/local/bin/emacs --script
;;-*- mode: emacs-lisp;-*-

(defun process (string)
 "just reverse the string"
  (concat (nreverse (string-to-list string))))

(condition-case nil
    (let (line)
      ;; commented out b/c not relevant for `cat`, but potentially useful
      ;; (princ"argv is")
      ;; (princ argv)
      ;; (princ"\
")
      ;; (princ"command-line-args is" )
      ;; (princ command-line-args)
      ;; (princ"\
")

      (while (setq line (read-from-minibuffer""))
        (princ (process line))
        (princ"\
")))
  (error nil))

现在,如果您有一个名为stuff.txt的文件,其中包含

1
2
3
abcd
1234
xyz

然后您像上面这样调用了上面编写的shell脚本(假设它名为rcat):

1
rcat < stuff.txt

您将看到以下打印到标准输出:

1
2
3
dcba
4321
zyx

因此,与普遍的看法相反,您实际上可以在stdin上执行批处理文件,而不必一次读取整个文件。


这是我想出的。 对我来说看起来更惯用:

1
2
3
4
5
6
7
8
9
10
(with-temp-buffer
  (let ((dest-buffer (current-buffer)))
    (with-temp-buffer
      (insert-file-contents"/path/to/source/file")
      (while (search-forward-regexp".*\
\\\\|.+" nil t)
        (let ((line (match-string 0)))
          (with-current-buffer dest-buffer
            (insert (process line)))))))
  (write-file"/path/to/dest/file" nil))

Emacs Lisp不适合处理文件流。 整个文件必须立即读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
(defun my-line-fun (line)
  (concat"prefix:" line))

(let* ((in-file"in")
       (out-file"out")
       (lines (with-temp-buffer
        (insert-file-contents in-file)
        (split-string (buffer-string) "\
\
?"))))
  (with-temp-file out-file
    (mapconcat 'my-line-fun lines"\
")))