Bash 脚本:某些命令失败。要求用户继续执行下一个命令或编辑先前失败的命令并重新运行它,然后继续执行下一个命令

Bash 脚本:某些命令失败。要求用户继续执行下一个命令或编辑先前失败的命令并重新运行它,然后继续执行下一个命令

我有剧本。我想做的是

  • 当某些命令失败时(注意条件不匹配不能被视为失败)
  • 仅当某些命令失败时,脚本才应暂停并向用户显示失败的命令并询问用户是否要编辑该命令
  • 如果用户输入“y”,则会在 vim 中打开命令,其中用户将编辑错误的命令并使用新命令恢复脚本。
  • 或者如果用户输入“n”通常继续下一个命令

需要开发上述方法

到目前为止我推断出以下机制

trap rerun ERR 
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG  

#也许使用上面我们可以将每个命令存储在前一个命令变量中。因此,当命令失败时,可以使用先前的命令变量获取该命令字符串

rerun() {
echo "$previous_command" | vim - 
#OR vim <(echo "$previous_command")
}

想要一种方法将先前的命令回显给 vim 并让用户编辑它并执行它。

[
simple way: echo previous command >> tmpfile
vi tmpfile

#now user will edit it and save and exit
then 
eval "$(cat tmpfile)"
]

但我想要一个无文件解决方案,没有临时文件,以编程方式使用 ctrl+x ctrl+e

要点
我们可以重新运行

rerun() {
echo "$previous_command" | vim - 
#OR vim <(echo "$previous_command")
}

如何在当前 shell 上下文中编辑后执行它 另外,如果命令在重新运行函数后第二次失败,则不应捕获错误并继续执行下一个命令并记录失败的命令

也许 fc 命令可以帮助编辑和执行

到目前为止我推断如下。将以下内容添加到 shell 脚本的开头

rerun() {
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then :; fi
}
trap rerun ERR 
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG  

但上面我没有测试过。欢迎任何更强大的解决方案。

我还想采用一种机制,当命令失败时,重新运行由陷阱执行。但即使重新运行后,如果命令第二次失败,则不要执行重新运行并继续执行下一个命令

对于上述问题我尝试过:

rerun() {
if [[ -n "$norepeat" ]]; then unset norepeat
elif [[ -z "$norepeat" ]]; then
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; [[ "$?" != "0" ]] && norepeat=1; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then norepeat=1; fi
}
trap rerun ERR 
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG

描述: 第一次出错时,将执行重新运行并要求用户继续或编辑并执行。在“Y”提示符下,它将使用 fc 命令执行最后一个命令,并测试执行的命令是否没有退出状态为零,即命令第二次失败并设置 norepeat=1;由于命令由于错误而第二次失败,重新运行将再次执行。但这一次,由于设置了 norepeat,它将不会运行 fc,但会取消设置 norepeat,并且脚本将继续执行下一个命令。现在,如果另一个命令失败,将调用重新运行,但由于 norepeat 已取消设置,它将运行 fc 命令。

上面没有测试过。不确定 fc 命令 $ 之后?将实际测试 fc 命令或重新编辑重新执行命令的退出代码

欢迎对我的方法和任何其他强大的解决方案提出批评和改进。请帮忙。

另一件需要的事情是命令第二次失败时将其记录到 failed.log#因为第二次失败时我不确定 previous_command 将设置为“fc commamd”或“重新执行的命令”

对上述的建议:在重新运行函数内部,我们可以捕获$LINENO第一个命令,并在设置 norepeat 后的 fc 命令之后,我们可以echo "$LINENO" >> failed.logsed ''"$LINENO"'p' -En "$0" >> failed.log 如下所示(不确定是否有效)

rerun() {
failed_lineno="$LINENO"
if [[ -n "$norepeat" ]]; then unset norepeat
elif [[ -z "$norepeat" ]]; then
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; [[ "$?" != "0" ]] && { norepeat=1; sed ''"$failed_lineno"'p' -En "$0" >> failed.log; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then norepeat=1; fi
}
trap rerun ERR 
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG

答案1

我认为,这是一种完全错误的做法。如果“编辑”命令与手头的任务无关怎么办?如果用户在 vim 中打开“失败的命令”,去吃午饭,忘记了任务怎么办?如果编辑的命令本身失败并且用户不知道原因怎么办?

如果您有一项复杂的任务,并且您预计其中的某些步骤容易失败。例如,您可以安装由多个模块组成的复杂应用程序,并且需要在运行中进行调整以适应不同的硬件/操作系统。这些任务通常通过一堆菜单来解决,其中每个主要步骤(要下载哪些模块,从哪个镜像进行下载等)的组织方式如下:

# make a menu function
choose_modules() {
echo -ne "
a) Use module A
b) Use module B
c) Use module C
z) done"

read a
case $a in
  a) use_module_a=yes ; choose_modules;;
  b) use_module_b=yes ; choose_modules;;
  c) use_module_c=yes ; choose_modules;;
  z) exit 0 ;;
  *) echo "Wrong option" ; choose_modules;;
esac
}

# the main script starts with a forever loop
while true
do

use_module_a=no
use_module_b=no
use_module_c=no

choose_modules

if [ $use_module_a = "yes" ] ; then
   # some commands for this option
fi

if [ $use_module_b = "yes" ] ; then
   # some commands for this option
fi

if [ $use_module_c = "yes" ] ; then
   # some commands for this option
fi

# at the end of the loop, ensure that we have at least one module,
# if yes - exit the loop, if not a single module installed - restart the loop
if [ $have_module_a=yes -o $have_module_b=yes -o $have_module_c=yes ] ; then
   break
fi
done

您可以为用户可以做的任何重要决定提供这样的菜单

相关内容