在shell中捕获启动运行进程的命令

时间:2018-07-31 10:14:49

标签: shell zshrc

我尝试使 GNU屏幕中的窗口标题自动等于工作目录的路径 PLUS (如果存在的话)正在运行的进程(例如:< em> npm start 或 vim file.js

为此,我在.zshrc中添加了以下行:

precmd () {
  local action = action_to_define
  if [[ $TERM == screen* ]]; then
    printf -Pn '\ek%~ $action\e\\'
  fi
}

这将(以某种方式)发送路径作为屏幕标题(请参见this post

和变量 action 将显示正在运行的程序(如果存在)

我尝试了local action= $(history | tail -1 | sed 's#[0-9 ]*##'),因为它选择了历史记录中的最后一条命令的提示(就像history !!会在选项!!被识别的情况下那样,这并非出于某种原因)。 ..)

local action= $(ps -lr | tail -1 | sed 's#^.*:...##'),因为这会选择正在运行的进程的命令

但是它不起作用,好像该进程没有被历史记录或ps捕获一样……也许precmd在启动动作之前就运行了,所以我尝试了其他功能,例如preexeczshaddhistory没有任何运气...

1 个答案:

答案 0 :(得分:1)

precmd钩子仅在命令完成后才显示下一个提示之前运行。因此,它可以用于更改提示显示时的终端标题。为了在运行命令时更改终端标题,您需要一个preexec钩子,该钩子在接受命令后运行(在运行命令之前,按 Enter 之后)。

在提示符下确认命令时,此命令将以三种形式作为参数传递给preexec

  1. 第一个参数是键入的字符串,包括任何换行符(只要历史记录机制处于活动状态,通常是这样)
  2. 第二个参数是一行,扩展名是命令的大小受限制的版本(如果太长会被截断)。
  3. 第三个参数是实际运行的命令的全文(具有扩展的别名)

这应该可以解决问题:

preexec () {
  local action="$1"
  if [[ $TERM == screen* ]]; then
    printf -Pn '\ek%~ $action\e\\'
  fi
}

由于precmd钩子仅在提示下一条命令之前运行,因此可以简化它:

precmd () {
  if [[ $TERM == screen* ]]; then
    printf -Pn '\ek%~\e\\'
  fi
}

尽管这不是它不起作用的主要原因,但必须注意,在Zsh(和大多数其他Unix shell)中,在给参数赋值时,=前后不能有空格。

确切的行为可能会有所不同,具体取决于放置空格的位置以及使用localset之类的东西还是仅使用简单的赋值。

以问题中的代码为例:

  • =local之前和之后放置空格通常会导致错误的分配

    % local action = action_to_define
    zsh: bad assignment
    
  • 仅在=后使用local放置空格,这将为变量分配一个空字符串,并创建/设置另一个空变量或导致上下文错误,具体取决于预期值是否可行参数名称:

     % local action= "echo" 
    

    这将清空actionecho

     % local action= "echo foo"
     local: not valid in this context: echo foo
    

    这里action也被清空,但是local之后失败了,因为由于包含空格,echo foo不是可行的参数名称。