fork download
  1. ;; Two reader macros to help interaction with the shell, from the REPL.
  2. ;; You may put that in your rc files.
  3.  
  4.  
  5. ;; A dispatching reader macro for #! lines, so that you may load lisp scripts.
  6. ;; It may be advisable to guard the entry point of the script; I use:
  7. ;; #-testing (main)
  8. ;; and I have (push :testing *features*) in my REPL rc files
  9. ;; (that are not loaded by my scripts).
  10. ;; Thus, I can load the scripts without executing them, and I can try and
  11. ;; debug them in the REPL.
  12.  
  13. (defun executable-reader (stream ch subch)
  14. (declare (ignorable ch subch))
  15. #+clisp (sys::unix-executable-reader stream ch subch)
  16. #-clisp (progn
  17. (read-line stream)
  18. (values)))
  19. (set-dispatch-macro-character #\# #\! (function executable-reader))
  20.  
  21.  
  22. ;; Then, a reader macro on ! to read and run shell commands.
  23. ;; 1- the reader macro reads a form. So you can see what it without
  24. ;; executing the command by quoting it:
  25. ;; '!ls -la
  26. ;; 2- status is stored in *shell-command-status* if you need to test it
  27. ;; (eg. in a script).
  28. ;; 3- before executing the command, it sources ~/.bashrc, and it pipes the
  29. ;; command thru expand -8 to expand the tabs. uiop:run-program doesn't
  30. ;; use a pty/tty, so we cannot use stty to deal with tabs.
  31. ;; 4- the lines following the ! reader macro may be terminated with a backslash,
  32. ;; and continued on the following line. All the lines are copied as-is
  33. ;; (with the backslash and newline) to the script, until a line without final
  34. ;; backslash is read.
  35. ;; Example:
  36. ;; ! ls \
  37. ;; -l \
  38. ;; -a
  39. ;;
  40. (defvar *shell-command-status* 0)
  41. (defun shell-escape (stream ch)
  42. (declare (ignore ch))
  43. `(progn
  44. (setf *shell-command-status*
  45. (nth-value 2
  46. (uiop:run-program
  47. ,(with-output-to-string (out)
  48. (write-string "source ~/.bashrc ; ( " out)
  49. (loop
  50. :for line := (read-line stream nil nil)
  51. :while (and line (char= #\\ (aref line (1- (length line)))))
  52. :do (write-line line out)
  53. :finally (write-string line out))
  54. (write-string " ) | expand -8" out))
  55. :input nil
  56. :output t
  57. :error-output t
  58. :ignore-error-status t
  59. :force-shell t)))
  60. (values)))
  61. (set-macro-character #\! 'shell-escape)# your code goes here
  62.  
  63.  
  64. ;; Have fun!
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
; compiling file "/home/zDaGKQ/prog.lisp" (written 18 MAY 2021 07:51:39 PM):
; compiling (DEFUN EXECUTABLE-READER ...)
; compiling (SET-DISPATCH-MACRO-CHARACTER #\# ...)
; compiling (DEFVAR *SHELL-COMMAND-STATUS* ...); 
; caught ERROR:
;   READ error during COMPILE-FILE:
;   
;     Package UIOP does not exist.
;   
;       Line: 47, Column: -1, File-Position: 1800
;   
;       Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/zDaGKQ/prog.lisp" {1001B885C3}>
; 
; compilation unit aborted
;   caught 1 fatal ERROR condition
;   caught 1 ERROR condition

; compilation aborted after 0:00:00.056
Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                    {10005D05B3}>:
  compilation failed

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005D05B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SIMPLE-ERROR "compilation failed" {1001BAD093}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SIMPLE-ERROR "compilation failed" {1001BAD093}>)
2: (INVOKE-DEBUGGER #<SIMPLE-ERROR "compilation failed" {1001BAD093}>)
3: (ERROR "compilation failed")
4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ERROR "compilation failed") #<NULL-LEXENV>)
5: (SB-INT:SIMPLE-EVAL-IN-LEXENV (WHEN (NTH-VALUE 2 (COMPILE-FILE "prog.lisp")) (ERROR "compilation failed")) #<NULL-LEXENV>)
6: (EVAL (WHEN (NTH-VALUE 2 (COMPILE-FILE "prog.lisp")) (ERROR "compilation failed")))
7: (SB-IMPL::PROCESS-EVAL/LOAD-OPTIONS ((:EVAL . "(when(nth-value 2(compile-file \"prog.lisp\"))(error \"compilation failed\"))") (:EVAL . "(quit)")))
8: (SB-IMPL::TOPLEVEL-INIT)
9: ((FLET SB-UNIX::BODY :IN SAVE-LISP-AND-DIE))
10: ((FLET "WITHOUT-INTERRUPTS-BODY-14" :IN SAVE-LISP-AND-DIE))
11: ((LABELS SB-IMPL::RESTART-LISP :IN SAVE-LISP-AND-DIE))

unhandled condition in --disable-debugger mode, quitting
stdout
Standard output is empty