0

I have script. I want to do is

  • when some command fails (note conditionals not matching must not be considered as fail)
  • only when certain command fails script should pause and display user the failed command and ask user if want to edit the command
  • if user input "y" then it opens command in vim wherein user would edit the wrong command and resume script with new command.
  • or if user input "n" normally continue to next command

need to develop above approach with

So far I deduced following mechanism

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

#maybe using above we can store each command in previous command variable. so when command fails, that command string can be obtained using previous command variable

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

want a way to echo previous command to vim and let user edit it and execute it.

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

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

But I want a fileless solution no temp file employing ctrl+x ctrl+e programatically

Important Points
We can on rerun

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

how to execute it after editing in current shell context also if command fails second time after rerun function then thar err should not be trapped and continue to next command and log the failed command

Maybe fc command can help edit and execute

So far I deduced below. Add below to beginning of shell script

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  

But i haven't tested above. Any more robust solution are welcomed.

Also i want to employ mechanism that when a command fails rerun is executed by trap. But even after rerun if command fails second time then dont execute rerun and continue to next command

To above problem i tried:

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

Description: On first err the rerun wil be executed and ask user to continue or edit and execute. On "Y" prompt, it will use fc command to execute the last command and test if command executed has no exit status zero i.e, command failed second time and set norepeat=1; since commmand failed second time due to err rerun will be executed again. But this time since norepeat has been set it will not run fc, but will unset norepeat and the script continues to next command. Now if another command fails rerun will be called but since norepeat has been unset it will run fc command.

Havent tested above. Not sure that after fc command $? will actually test the exit code of fc command or the re-edited-re-executed command

Critics and improvements to my approach and any other robust solutions are welcomed. Please Help.

Another thing need is to on command fails second time log it to failed.log #Because on second time fail i am not sure previous_command will be set to "fc commamd" or "re-executed command"

A proposal to above: Inside rerun function we can capture $LINENO as first command and after fc command while setting norepeat we can echo "$LINENO" >> failed.log OR sed ''"$LINENO"'p' -En "$0" >> failed.log As Below (Not sure would work or not

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 Answer 1

0

I think, it is a completely wrong approach. What if the "edited" command have nothing to do with the task at hand? What if user opens "failed command" in vim, goes to lunch, forget about the task? What if the edited command is failing by itself and user have no idea why that is?

If you have a complicated task, and you expect some steps in it to be prone to failure. For example, you can install a complicated application consisting from several modules and you need to adjust mid-run to accommodate different hardware/OS. These tasks are usually solved by a bunch of menus, where each major step (which modules to download, from which mirror do the downloading, etc) is organized in something like:

# 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

And you can have such menus for any important decision a user can do

2
  • can you give working example for my need based on your approach instead of template
    – Edward
    Feb 16, 2023 at 16:43
  • seems you did not read my need question. i am not asking for how to handle a complicated task. my need is clear. read question. on failyre of a command i would like user to edit the failed command and execute it . and if still it fails seconf time ignore error trap this time and continue to next command. do this for all co.mands that fail
    – Edward
    Feb 16, 2023 at 16:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .