2012-07-26 34 views
5

Quiero ejecutar el siguiente script bash, que está almacenado en una cadena Elisp, no en un archivo .sh, y luego almacenar el resultado del shell en una variable.Ejecutar secuencia de comandos bash bash desde Emacs

#!/bin/bash 
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##*/}" 
    done 
done 

no podía correr shell-command en scripts bash, que consiste en varias cadenas. Emacs and Long Shell Commands tampoco me ayudó, ya que compile y comint-run también requieren comandos, no la sintaxis bash.

¿Cómo ejecuto un script bash complejo de Elisp?

+0

si Mx región shell-command-en-falla , envíe un informe de error –

Respuesta

6

comandos de varias líneas son finas para proveer como un argumento a bash -c si se les cita como lo haría con cualquier otro argumento cáscara que podría contener metacaracteres de shell, por ejemplo:

(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))) 
2

Esto quizás haga lo que quiera. Añadir modificadores al gusto :)

(defun example-multiline-shell-command() 
    (interactive) 
    (with-temp-buffer 
    (insert "#!/bin/bash 
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##*/}\" 
    done 
done") 
    (write-region (point-min) (point-max) "~/temp.sh") 
    (shell-command "source ~/temp.sh" (current-buffer)) 
    (buffer-string))) 

EDITAR Ah, y FYI "${_dirs_in_path[@]}" se va a acabar mal si los archivos tienen espacios u otros caracteres que podrían ser tratadas como separadores en los nombres.

+0

No, la sintaxis '" $ {arrayvar [@]} "' es perfectamente segura independientemente de la presencia de metacaracteres de shell en cualquier elemento de 'arrayvar'. – Sean

0

shell-command en realidad funciona en la sintaxis bash de cadenas múltiples. Mi problema fue que shell-command no conoce las variables de entorno bash, incluida PATH. Lo que hice: reemplacé todos " con \" en el script y lo puse en una cadena elisp, luego asigné algunos directorios a PATH. Aquí está el código, que arroja con éxito todos los ejecutables en el sistema al buffer *Shell Command Output*.

(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##*/}\" 
    done 
done")) 
    (shell-command (concat path ";" command))) 

Todavía estoy interesado en cómo hacer compile trabajo con scripts bash de cadena múltiple también.

Nota sobre la RUTA: No utilizar (getenv "PATH") en la solución anterior, ya que, por lo que entiendo, los administradores de pantalla X (incluyendo xdm, gdm y kdm) do not run shell before Xsession, por lo que un emacs van de interfaz gráfica de usuario tendrán diferentes variables de entorno de los bash. Ejecuto emacs --daemon en el inicio a través de cron, mis rutas están configuradas en /etc/profile y ~/.profile, por lo que Emacs no obtiene su ruta desde allí.

Steve Purcell propone un code (véase también la variante one y two de ella en SO) para asegurarse de que Emacs tiene las mismas variables de entorno, incluyendo el camino, como la cáscara.

Cuestiones relacionadas