# -*- commonlisp -*- # hello world # print a simple string on stdout (format t "Hello world~%") # argv # access command line parameters (no segmentation fault accepted, nor silent exception, so some languages must explicitly check the presence of the argument) (write-line (second *posix-argv*)) # env # access environment variable (write-line (posix-getenv "HOME")) # test file exists # return exit code error (non zero) if a file does not exist (unless (probe-file "/etc/mtab") (quit :unix-status 1)) # test file readable # return exit code error (non zero) if a file is not readable (require :sb-posix) (unless (sb-posix:access "/etc/mtab" r-ok) (quit :unix-status 1)) # formatting # print integers in a simple formatted string (let ((a 1) (b 2)) (format t "~a + ~a = ~a~%" a b (+ a b))) # system # call an external program and check the return value (unless (zerop (process-exit-code (run-program "false" nil :search t))) (format *error-output* "false failed~%")) (run-program "echo" '("done") :search t :output *standard-output*) # sed in place # remove #-comments from a file (modifying the file, i.e. in place) (defun remove-hash-comments (path) (let ((lines (with-open-file (inf path :direction :input) (loop for line = (read-line inf nil nil) while line collect line)))) (with-open-file (ouf path :direction :output :if-exists :supersede) (dolist (line lines) (write-line (subseq line 0 (position #\# line)) ouf))))) # compile what must be # find and compile .c files into .o when the .o is old or absent (defun find-files-by-type (dir type) (mapcan (lambda (path) (cond ((null (pathname-name path)) (find-files-by-type path type)) ((string= (pathname-type path) type) (list path)) (t nil))) (directory (make-pathname :name :wild :type :wild :defaults (truename dir)))))) (defun compile-older-files (dir) (dolist (c-path (find-files-by-type dir "c")) (let* ((c-name (namestring c-path)) (o-path (make-pathname :type "o" :defaults c-path)) (o-name (namestring o-path))) (when (or (not (probe-file o-path)) (< (file-write-date o-path) (file-write-date c-path))) (format t "Compiling ~a to ~a~%" c-name o-name) (run-program "gcc" (list "-c" "-o" o-name c-name) :output *standard-output* :search t))))) # grep # grep with -F -i -h handling, usage, grep'ing many files (require :asdf) (require :cl-ppcre) (defun grep (pattern files &key (no-case nil) (fixed-strings nil)) (let ((scanner (cl-ppcre:create-scanner (if fixed-strings (cl-ppcre:quote-meta-chars pattern) pattern) :case-insensitive-mode no-case)) (prefix-p (> (length files) 1))) (dolist (path files) (with-open-file (inf path :direction :input) (loop for line = (read-line inf nil nil) while line when (cl-ppcre:scan scanner line) do (format t "~@[~a:~]~a~%" (when prefix-p (pathname-name path)) line)))))) (defun parse-args (argv) (let ((flags nil) (args nil)) (dolist (arg argv) (if (eql (char arg 0) #\-) (push arg flags) (push arg args))) (values (nreverse flags) (nreverse args)))) (multiple-value-bind (flags args) (parse-args (rest *posix-argv*)) ;; Handle help flag (when (or (null args) (member "-h" flags :test #'string=)) (format *error-output* "Usage: grep [-h] [-i] [-F] ...~%") (quit :unix-status 1)) ;; Do grep (grep (first args) (rest args) :no-case (member "-i" flags :test #'string=) :fixed-strings (member "-F" flags :test #'string=)))