Emacs执行shell-command-to-shell命令报错

  • 从清华镜像下载的emacs27.2源码编译
  • Ubuntu2004
  • 执行counsel-projectile-switch-project报错,错误如下
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  call-process(nil nil (t "/tmp/scorV2Q5AB") nil "-c" "git ls-files -zco --exclude-standard")
  call-process-shell-command("git ls-files -zco --exclude-standard" nil (t "/tmp/scorV2Q5AB"))
  shell-command("git ls-files -zco --exclude-standard" t "*projectile-files-errors*")
  projectile-files-via-ext-command("/home/linglx/Projects/Practice/OpenCV/MatTest/" "git ls-files -zco --exclude-standard")
  projectile-dir-files-alien("/home/linglx/Projects/Practice/OpenCV/MatTest/")
  projectile-dir-files("/home/linglx/Projects/Practice/OpenCV/MatTest/")
  #f(compiled-function (dir) #<bytecode 0x156c8dbd8aa5>)("/home/linglx/Projects/Practice/OpenCV/MatTest/")
  mapcan(#f(compiled-function (dir) #<bytecode 0x156c8dbd8aa5>) ("/home/linglx/Projects/Practice/OpenCV/MatTest/"))
  cl-mapcan(#f(compiled-function (dir) #<bytecode 0x156c8dbd8aa5>) ("/home/linglx/Projects/Practice/OpenCV/MatTest/"))
  projectile-project-files("/home/linglx/Projects/Practice/OpenCV/MatTest/")

  • 发现是shell-command-to-string命令有错误,测试其它命令(ls),报错如下:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  call-process(nil nil t nil "-c" "ls")
  call-process-shell-command("ls" nil t)
  #f(compiled-function (command &optional output-buffer error-buffer) "Execute string COMMAND in inferior shell; display output, if any.\nWith prefix argument, insert the COMMAND's output at point.\n\nInteractively, prompt for COMMAND in the minibuffer.\nIf `shell-command-prompt-show-cwd' is non-nil, show the current\ndirectory in the prompt.\n\nIf COMMAND ends in `&', execute it asynchronously.\nThe output appears in the buffer `*Async Shell Command*'.\nThat buffer is in shell mode.  You can also use\n`async-shell-command' that automatically adds `&'.\n\nOtherwise, COMMAND is executed synchronously.  The output appears in\nthe buffer `*Shell Command Output*'.  If the output is short enough to\ndisplay in the echo area (which is determined by the variables\n`resize-mini-windows' and `max-mini-window-height'), it is shown\nthere, but it is nonetheless available in buffer `*Shell Command\nOutput*' even though that buffer is not automatically displayed.\n\nTo specify a coding system for converting non-ASCII characters\nin the shell command output, use \\[universal-coding-system-argument] before this command.\n\nNoninteractive callers can specify coding systems by binding\n`coding-system-for-read' and `coding-system-for-write'.\n\nThe optional second argument OUTPUT-BUFFER, if non-nil,\nsays to put the output in some other buffer.\nIf OUTPUT-BUFFER is a buffer or buffer name, erase that buffer\nand insert the output there; a non-nil value of\n`shell-command-dont-erase-buffer' prevents the buffer from being\nerased.  If OUTPUT-BUFFER is not a buffer and not nil (which happens\ninteractively when the prefix argument is given), insert the\noutput in current buffer after point leaving mark after it.  This\ncannot be done asynchronously.\n\nThe user option `shell-command-dont-erase-buffer', which see, controls\nwhether the output buffer is erased and where to put point after\nthe shell command.\n\nIf the command terminates without error, but generates output,\nand you did not specify \"insert it in the current buffer\",\nthe output can be displayed in the echo area or in its buffer.\nIf the output is short enough to display in the echo area\n(determined by the variable `max-mini-window-height' if\n`resize-mini-windows' is non-nil), it is shown there.\nOtherwise, the buffer containing the output is displayed.\n\nIf there is output and an error, and you did not specify \"insert it\nin the current buffer\", a message about the error goes at the end\nof the output.\n\nIf the optional third argument ERROR-BUFFER is non-nil, it is a buffer\nor buffer name to which to direct the command's standard error output.\nIf it is nil, error output is mingled with regular output.\nIn an interactive call, the variable `shell-command-default-error-buffer'\nspecifies the value of ERROR-BUFFER.\n\nIn Elisp, you will often be better served by calling `call-process' or\n`start-process' directly, since they offer more control and do not\nimpose the use of a shell (with its need to quote arguments)." (interactive #f(compiled-function () #<bytecode 0x158c28dd8bb1>)) #<bytecode 0x1fd9fa5f0b15>)("ls" t nil)
  shell-command--shell-command-with-editor-mode(#f(compiled-function (command &optional output-buffer error-buffer) "Execute string COMMAND in inferior shell; display output, if any.\nWith prefix argument, insert the COMMAND's output at point.\n\nInteractively, prompt for COMMAND in the minibuffer.\nIf `shell-command-prompt-show-cwd' is non-nil, show the current\ndirectory in the prompt.\n\nIf COMMAND ends in `&', execute it asynchronously.\nThe output appears in the buffer `*Async Shell Command*'.\nThat buffer is in shell mode.  You can also use\n`async-shell-command' that automatically adds `&'.\n\nOtherwise, COMMAND is executed synchronously.  The output appears in\nthe buffer `*Shell Command Output*'.  If the output is short enough to\ndisplay in the echo area (which is determined by the variables\n`resize-mini-windows' and `max-mini-window-height'), it is shown\nthere, but it is nonetheless available in buffer `*Shell Command\nOutput*' even though that buffer is not automatically displayed.\n\nTo specify a coding system for converting non-ASCII characters\nin the shell command output, use \\[universal-coding-system-argument] before this command.\n\nNoninteractive callers can specify coding systems by binding\n`coding-system-for-read' and `coding-system-for-write'.\n\nThe optional second argument OUTPUT-BUFFER, if non-nil,\nsays to put the output in some other buffer.\nIf OUTPUT-BUFFER is a buffer or buffer name, erase that buffer\nand insert the output there; a non-nil value of\n`shell-command-dont-erase-buffer' prevents the buffer from being\nerased.  If OUTPUT-BUFFER is not a buffer and not nil (which happens\ninteractively when the prefix argument is given), insert the\noutput in current buffer after point leaving mark after it.  This\ncannot be done asynchronously.\n\nThe user option `shell-command-dont-erase-buffer', which see, controls\nwhether the output buffer is erased and where to put point after\nthe shell command.\n\nIf the command terminates without error, but generates output,\nand you did not specify \"insert it in the current buffer\",\nthe output can be displayed in the echo area or in its buffer.\nIf the output is short enough to display in the echo area\n(determined by the variable `max-mini-window-height' if\n`resize-mini-windows' is non-nil), it is shown there.\nOtherwise, the buffer containing the output is displayed.\n\nIf there is output and an error, and you did not specify \"insert it\nin the current buffer\", a message about the error goes at the end\nof the output.\n\nIf the optional third argument ERROR-BUFFER is non-nil, it is a buffer\nor buffer name to which to direct the command's standard error output.\nIf it is nil, error output is mingled with regular output.\nIn an interactive call, the variable `shell-command-default-error-buffer'\nspecifies the value of ERROR-BUFFER.\n\nIn Elisp, you will often be better served by calling `call-process' or\n`start-process' directly, since they offer more control and do not\nimpose the use of a shell (with its need to quote arguments)." (interactive #f(compiled-function () #<bytecode 0x158c29297745>)) #<bytecode 0x1fd9fa5f0b15>) "ls" t)
  apply(shell-command--shell-command-with-editor-mode #f(compiled-function (command &optional output-buffer error-buffer) "Execute string COMMAND in inferior shell; display output, if any.\nWith prefix argument, insert the COMMAND's output at point.\n\nInteractively, prompt for COMMAND in the minibuffer.\nIf `shell-command-prompt-show-cwd' is non-nil, show the current\ndirectory in the prompt.\n\nIf COMMAND ends in `&', execute it asynchronously.\nThe output appears in the buffer `*Async Shell Command*'.\nThat buffer is in shell mode.  You can also use\n`async-shell-command' that automatically adds `&'.\n\nOtherwise, COMMAND is executed synchronously.  The output appears in\nthe buffer `*Shell Command Output*'.  If the output is short enough to\ndisplay in the echo area (which is determined by the variables\n`resize-mini-windows' and `max-mini-window-height'), it is shown\nthere, but it is nonetheless available in buffer `*Shell Command\nOutput*' even though that buffer is not automatically displayed.\n\nTo specify a coding system for converting non-ASCII characters\nin the shell command output, use \\[universal-coding-system-argument] before this command.\n\nNoninteractive callers can specify coding systems by binding\n`coding-system-for-read' and `coding-system-for-write'.\n\nThe optional second argument OUTPUT-BUFFER, if non-nil,\nsays to put the output in some other buffer.\nIf OUTPUT-BUFFER is a buffer or buffer name, erase that buffer\nand insert the output there; a non-nil value of\n`shell-command-dont-erase-buffer' prevents the buffer from being\nerased.  If OUTPUT-BUFFER is not a buffer and not nil (which happens\ninteractively when the prefix argument is given), insert the\noutput in current buffer after point leaving mark after it.  This\ncannot be done asynchronously.\n\nThe user option `shell-command-dont-erase-buffer', which see, controls\nwhether the output buffer is erased and where to put point after\nthe shell command.\n\nIf the command terminates without error, but generates output,\nand you did not specify \"insert it in the current buffer\",\nthe output can be displayed in the echo area or in its buffer.\nIf the output is short enough to display in the echo area\n(determined by the variable `max-mini-window-height' if\n`resize-mini-windows' is non-nil), it is shown there.\nOtherwise, the buffer containing the output is displayed.\n\nIf there is output and an error, and you did not specify \"insert it\nin the current buffer\", a message about the error goes at the end\nof the output.\n\nIf the optional third argument ERROR-BUFFER is non-nil, it is a buffer\nor buffer name to which to direct the command's standard error output.\nIf it is nil, error output is mingled with regular output.\nIn an interactive call, the variable `shell-command-default-error-buffer'\nspecifies the value of ERROR-BUFFER.\n\nIn Elisp, you will often be better served by calling `call-process' or\n`start-process' directly, since they offer more control and do not\nimpose the use of a shell (with its need to quote arguments)." (interactive #f(compiled-function () #<bytecode 0x158c292b5b29>)) #<bytecode 0x1fd9fa5f0b15>) ("ls" t))
  shell-command("ls" t)
  shell-command-to-string("ls")
  eval((shell-command-to-string "ls") nil)
  pp-eval-expression((shell-command-to-string "ls"))
  funcall-interactively(pp-eval-expression (shell-command-to-string "ls"))
  call-interactively(pp-eval-expression nil nil)
  command-execute(pp-eval-expression)

不知大家是否遇到到,已经在doom emacs、projectile、counsel-projectile找过issue,没有什么发现,也google过没有答案,尝试重新编译到emacs,也没效果,所以上来问问大家了。

没看出来报的什么错,贴出来的是 backtrace 调用的函数及其参数,没有错误本身

估计错误信息是 Debugger entered–Lisp error: (wrong-type-argument stringp nil)

call-process 的第一个参数为 nil,即没有找到 SHELL (对应 shell-file-name),尝试 Emacs -Q 重现

谢谢。错误是wrong type argument。我补充了。 call-process是emacs的一个API,接口(call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) 看是是调用call-process的入参写错了?

projectile-switch-project 代替好了,可以设置下

(setq projectile-completion-system 'ivy)

我没有用 counsel-projectile,不太清楚怎么回事,或许可以尝试报个 bug 什么的?

PS:shell-command-to-string 我这边 emacs 29 上是没有问题的,可能需要其他 27.2 的小伙伴看下有没有问题,不过这种基础的东西,又是 27.2 这种比较稳定的版本上,感觉出问题的可能性比较小。

PPS:你编译 emacs 之前用的是什么版本的 emacs?我印象中高版本退回到低版本,第三包最好重新编译下可能会比较好?

Emacs 本身几乎不可能会出现这个问题。也很难想象从 melpa 安装的包会造成这个问题。最有可能就是你配置里写的东西有问题。用 -Q 验证一下便知。

谢谢建议。真是惭愧,我不会裸用emads,只会用doom emacs

使用emacs -Q启动后,也只会加载去(load “~/.emacs.d/init.el”),后面就不会了。

谢谢,counsel-projectile后面也就调用了projectile-switch-project

谢谢。有了你的提示,我去看了call-process-shell-command的源码,它里面调用call-process时传入了shell-file-name,查看这个变量是nil值,看来是启动时把这个值搞丟了。默认是从环境变量SHELL里取的这个值。手动设置下(setq shell-file-name “/bin/sh”)就恢复了。

我用的doom emacs配置,也使用chsh -s /usr/bin/zsh将默认的SHELL改成了zsh。

算是定位到了问题,接下来看看为什么没有读取到SHELL。

推荐你看看本论坛站长制作的入门视频😄,最近刚制作 2022 版本

被自己坑到了,这得给自己来一拳。我的配置文件里竞然有(setq shell-file-name (executable-find "zsh.exe"))这条语句,看来是之前windows环境下使用emacs添加的,ubuntu不叫zsh.exe这个名称。血的教训。。。

但还是学习到了新的知识,感谢