从Emacs运行多字符串bash脚本



我想运行以下bash脚本,该脚本存储在Elisp字符串中,而不是.sh文件中,然后将shell输出存储在变量中。

#!/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 '%sn' "${_file##*/}"
    done
done

我无法在由多个字符串组成的bash脚本上运行shell-command。Emacs和Long Shell命令对我也没有帮助,因为compilecomint-run也需要命令,而不是bash语法。

如何从Elisp运行复杂的bash脚本

如果像引用任何其他可能包含外壳元字符的外壳参数一样引用多行命令,则可以将其作为参数提供给bash -c,例如:

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

这可能会达到您想要的效果。添加口味调节剂:)

(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 '%sn' "${_file##*/}"
    done
done")
    (write-region (point-min) (point-max) "~/temp.sh")
    (shell-command "source ~/temp.sh" (current-buffer))
    (buffer-string)))

EDIT哦,仅供参考,如果文件的名称中有空格或其他可能被视为分隔符的字符,那么"${_dirs_in_path[@]}"的结尾会很糟糕

shell-command实际上适用于多字符串bash语法。我的问题是shell-command不知道bash环境变量,包括PATH。我所做的:将脚本中的所有"替换为",并将其放入elisp字符串中,然后将一些目录分配给PATH。这是成功地将系统中的所有可执行文件输出到*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 '%sn' "${_file##*/}"
    done
done"))
  (shell-command (concat path ";" command)))

我仍然对如何使compile与多字符串bash脚本一起工作感兴趣。

关于PATH的注意:我在上面的解决方案中没有使用(getenv "PATH"),因为据我所知,X显示管理器(包括xdm、gdm和kdm)在Xsession之前不运行shell,所以从GUI运行的emacs将具有与bash不同的环境变量。我通过cron在启动时运行emacs --daemon,我的路径设置在/etc/profile~/.profile中,所以Emacs不会从那里获得其PATH。

Steve Purcell提出了一个代码(另请参阅SO中的变体一和变体二),以确保Emacs具有与shell相同的环境变量,包括PATH。

最新更新