You can copy the following Elisp code to your init files.
It contains a modified version of function eshell-source-file
.
Essentially I changed (insert-file-contents file)
to (insert string)
.
Furthermore I needed a minor modification of 'eshell-command-name
.
It also contains the function define-eshell-script
defining an Eshell command with a doc string and an Eshell script given by a string. The script takes care of the formalities for the script required by Eshell internals (e.g., correctly registering in the list variable eshell-complex-commands
). Those formalities make the newly defined command interruptible.
(require 'cl-lib) ;; for macro `cl-pushnew' (not autoloaded ?!)
(require 'esh-cmd) ;; for variable `eshell-complex-commands'
(defun eshell-source-string (string &optional args subcommand-p)
"Execute a series of Eshell commands in STRING, passing ARGS.
Comments begin with `#'."
(interactive "sString to be evaluated as eshell script: ")
(let ((orig (point))
(here (point-max))
(inhibit-point-motion-hooks t))
(goto-char (point-max))
(with-silent-modifications
;; FIXME: Why not use a temporary buffer and avoid this
;; "insert&delete" business? --Stef
(insert string)
(goto-char (point-max))
(throw 'eshell-replace-command
(prog1
(list 'let
(list (list 'eshell-command-name (list 'quote "source-string"))
(list 'eshell-command-arguments
(list 'quote args)))
(let ((cmd (eshell-parse-command (cons here (point)))))
(if subcommand-p
(setq cmd (list 'eshell-as-subcommand cmd)))
cmd))
(delete-region here (point))
(goto-char orig))))))
(defun define-eshell-script (cmd doc string)
"Define CMD as eshell script STRING with documentation DOC.
CMD can be a string or a symbol."
(let ((fun (intern (concat "eshell/" cmd))))
(fset fun
`(lambda (&rest args)
,doc
(eshell-source-string ,string args)))
(cl-pushnew cmd (default-value 'eshell-complex-commands) :test #'equal)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (derived-mode-p 'eshell-mode)
(cl-pushnew cmd eshell-complex-commands :test #'equal))))
(put fun 'eshell-no-numeric-conversions t)))
If the above functions are available you can define your actual script with the help of define-eshell-script
as follows.
(define-eshell-script "script" "The doc-string: Output 1, sleep, and output 2."
"bash -c \"echo 1; sleep 3; echo 2;\"
echo DONE")
The usage example in Eshell looks like you want it:
/Path/to/current/dir $ script
1
2
DONE
/Path/to/current/dir $