Run multi-string bash script from Emacs Run multi-string bash script from Emacs shell shell

Run multi-string bash script from Emacs


Multiline commands are fine to provide as an argument to bash -c if you quote them as you would any other shell argument that might contain shell metacharacters, e.g.:

(setq my-command      (concat "IFS=: read -ra dirs <<<\"$PATH\"\n"              "for dir in ${dirs[@]}; do\n"              " echo got dir \"$dir\"\n"              "done\n"))(shell-command (format "bash -c %s" (shell-quote-argument my-command)))


This will perhaps do what you want. Add modifiers to taste :)

(defun example-multiline-shell-command ()  (interactive)  (with-temp-buffer    (insert "#!/bin/bashIFS=: read -ra _dirs_in_path <<< \"$PATH\"for _dir in \"${_dirs_in_path[@]}\"; do    for _file in \"${_dir}\"/*; do        [[ -x ${_file} && -f ${_file} ]] && printf '%s\n' \"${_file##*/}\"    donedone")    (write-region (point-min) (point-max) "~/temp.sh")    (shell-command "source ~/temp.sh" (current-buffer))    (buffer-string)))

EDIT Oh, and FYI "${_dirs_in_path[@]}" is going to end bad if files have spaces or other characters that might be treated as separators in the names.


shell-command actually works on multi-string bash syntax. My problem was that shell-command doesn't know bash environment variables, including PATH. What i did: replaced all " with \" in the script and put it in an elisp string, then assigned some directories to PATH. Here is the code, that successfully outputs all executables in the system to the *Shell Command Output* buffer.

(let ((path "PATH='/usr/local/bin:/usr/bin:/bin'")      (command "IFS=: read -ra _dirs_in_path <<< \"$PATH\"for _dir in \"${_dirs_in_path[@]}\"; do    for _file in \"${_dir}\"/*; do        [[ -x ${_file} && -f ${_file} ]] && printf '%s\n' \"${_file##*/}\"    donedone"))  (shell-command (concat path ";" command)))

I'm still interested in how to make compile work with multi-string bash scripts too.

Note on PATH: I didn't use (getenv "PATH") in the above solution because, as far as i understand, X display managers (including xdm, gdm and kdm) do not run shell before Xsession, so an emacs run from GUI will have different environment variables from the bash ones. I run emacs --daemon on startup through cron, my paths are set up in /etc/profile and ~/.profile, so Emacs doesn't get its PATH from there.

Steve Purcell proposes a code (see also variant one and two of it on SO) to make sure Emacs has the same environment variables, including PATH, as the shell.