linux 如何让ctrl+c在与子shell命令交互时取消整个命令?

tv6aics1  于 2023-08-03  发布在  Linux
关注(0)|答案(2)|浏览(116)

我有一个简单的shell别名

alias fz='vim -p $(fzf -m)'

字符串
fzf是一个交互式的终端程序,只有当它终止时,才会在stdout上发送一个文件名列表。然后,它用于打开使用vim选择的文件。
现在的问题是,当我决定取消并按下ctrl+c时,shell继续运行,仍然打开vim(就好像我刚刚运行了vim -p)。这有点道理。
现在,解决当前问题的一个方法是简单地使我的别名更复杂,这样如果fzf的输出为空,它就不会启动vim。或者,如果fzf的退出代码不为零,我可能会做一些事情来中止启动vim。
然而,我很好奇当我按Ctrl + C键时,我如何命令我的shell终止这个fz。当我在subshell上下文中时,这是不可能的吗?我可以通过某种方式设置进程组id来实现这一点吗?
我尝试了set -m,但它没有改变行为。

ukdjmx9f

ukdjmx9f1#

使用Ctrl + C提前退出时,使调用fzf(或其他命令)的脚本退出

1.简单别名

这个方法的作用是:

# command
files_list=$(fzf -m) && vim -p $files_list

# alias
alias fz='$(fzf -m) && vim -p $files_list'

字符串
说明:
fzf正常退出时,它返回错误代码0(注意:你可以通过运行echo $?在它退出后读取返回代码)。但是,当fzf被Ctrl + C杀死时,它返回错误代码130&&部分的意思是“如果左边的部分为零,则只执行右边的部分”--这意味着左边的命令成功完成。因此,当您在fzf运行时按Ctrl + C时,它会返回错误代码130,并且右侧的部分永远不会执行。

2.更健壮的功能

但是,如果您需要执行任何更复杂的操作,请使用函数(如果您愿意,仍然可以在~/.bashrc~/.bash_aliases文件中)而不是别名。下面是一个函数形式的更健壮的别名示例。* 我写的别名上面的方式,我希望它会失败,如果你有空白或奇怪的字符在他们的文件名。* 然而,下面的函数应该工作,即使在这些情况下,我认为:

fz() {
    files_list="$(fzf -m)"
    return_code="$?"

    if [ "$return_code" -ne 0 ]; then
        echo "Nothing to do; fzf return_code = $return_code"
        return "$return_code"
    fi

    echo "FILES SELECTED:"
    echo "$files_list"

    # Convert the above list of newline-separated file names into an array
    # - See: https://stackoverflow.com/a/24628676/4561887
    SAVEIFS=$IFS   # Save current IFS (Internal Field Separator)
    IFS=$'\n'      # Change IFS to newline char
    files_array=($files_list) # split this newline-separated string into an array
    IFS=$SAVEIFS   # Restore original IFS

    # Call vim with each member of the array as an argument
    vim -p "${files_array[@]}"
}


注意:如果您不熟悉[函数(是的,这是一个函数名!)),运行man [man test以获取更多信息。[函数也称为test。这就是为什么函数名后面的参数之间需要空格--它们是函数的参数!]符号只是[test)函数所需的结束参数。

参考资料:

1.我的array_practice.sh bash脚本来自我的eRCaGuy_hello_world repo。这就是我学习和记录了很多东西的地方。
1.如何将参数数组传递给命令:如何在bash中创建和使用所有输入参数(“$@”)的备份副本?
1.如何将换行符分隔的字符串解析为元素数组:将多行字符串转换为数组
1.使用return提前退出bash函数:How to exit a function in bash

v2g6jxz6

v2g6jxz62#

我采用了一种类似的方法,其灵感来自于Gabriel's answer,但经过修改,使其对于配置为默认值的编辑器更简单、更动态。请注意,我已经将其调整为用于打开单个文件而不是多个文件,但这很容易改变:

fzfedit() {
  local sel="$(fzf)"
  # If the selected file exists, open it with $EDITOR
  [[ -e "$sel" ]] && $EDITOR "$sel"
}

字符串
或者更准确地说是一个别名:

alias fzfedit='sel=$(fzf) && test -e "$sel" && $EDITOR "$sel"'

相关问题