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")
}

現在のシェルコンテキストで編集後に実行する方法 また、関数を再実行した後にコマンドが2番目に失敗した場合は、エラーをキャプチャしないでください。次のコマンドを実行し続け、失敗したコマンドを記録します。

おそらく、fcコマンドは編集と実行に役立ちます。

これまで私が推論した内容は次のとおりです。シェルスクリプトの先頭に以下を追加します。

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  

しかし、上記はテストしませんでした。より強力なソリューションを歓迎します。

また、コマンドが失敗したときにトラップによって再実行が行われるメカニズムを実装したいと思います。ただし、再実行後もコマンドが2番目に失敗した場合は、再実行せずに次のコマンドを続行してください。

上記の問題について私は以下を試しました。

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コマンドを使用して最後のコマンドを実行し、実行されたコマンドがステータス0で終了していないかどうかをテストします。つまり、コマンドが2番目の失敗のため、norepeat = 1に設定されます。エラーのため、失敗すると再実行が再実行されます。ただし、今回はnorepeatが設定されているため、fcは実行されませんが、norepeatは設定解除され、スクリプトは次のコマンドを実行し続けます。他のコマンドが失敗した場合、rrun が呼び出されますが、norepeat が設定解除されたため、fc コマンドが実行されます。

上記はテストされていません。 $の後ろのfcコマンドがわからないのですか?実際にfcコマンドをテストするか、再実行されたコマンドの終了コードを再編集してください。

私のアプローチや他の強力なソリューションへの批判と改善を歓迎します。助けてください。

もう1つ必要なのは、2回目の失敗時にコマンドをfailed.logに書き込むことです。#2回目の失敗時に、前のコマンドが「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

ユーザーが行うことができる重要な決定についてこのようなメニューを提供できます。

関連情報