Title: Common LISP awk macro for easy text file operations Author: Solène Date: 04 February 2020 Tags: awk lisp Description: I like Common LISP and I also like awk. Dealing with text files in Common LISP is often painful. So I wrote a small awk like common lisp macro, which helps a lot dealing with text files. Here is the implementation, I used the uiop package for split-string function, it comes with sbcl. But it's possible to write your own split-string or reused the infamous split-str function shared on the Internet. (defmacro awk(file separator &body code) "allow running code for each line of a text file, giving access to NF and NR variables, and also to fields list containing fields, and line containing $0" `(progn (let ((stream (open ,file :if-does-not-exist nil))) (when stream (loop for line = (read-line stream nil) counting t into NR while line do (let* ((fields (uiop:split-string line :separator ,separator)) (NF (length fields))) ,@code)))))) It's interesting that the "do" in the loop could be replaced with a "collect", allowing to reuse awk output as a list into another function, a quick example I have in mind is this: ;; equivalent of awk '{ print NF }' file | sort | uniq ;; for counting how many differents fields long line we have (uniq (sort (awk "file" " " NF))) Now, here are a few examples of usage of this macro, I've written the original awk command in the comments in comparison: ;; numbering lines of a text file with NR ;; awk '{ print NR": "$0 }' file.txt ;; (awk "file.txt" " " (format t "~a: ~a~%" NR line)) last field in the list) ;; awk -F ';' '{ print NF-1 }' file.csv ;; (awk "file.csv" ";" (print (nth (- NF 2) fields))) ;; awk '/unbound/ { print }' /var/log/messages ;; (awk "/var/log/messages" " " (when (search "unbound" line) (print line))) ;; awk -F ';' '{ print $4 }' data.csv ;; (awk "data.csv" ";" (print (nth 4 fields))) |