4
#!/bin/sh
echo "install 1"
echo "install 2"
[ $? -eq 0 ] || exit $?;
cyberciti 
[ $? -eq 0 ] || exit $?;
echo "install 3"
echo "install 4"

The above script fails at line 4 (cyberciti). How can I take the line number, and re-run the script starting from that line, after making the required corrections, skipping already executed commands?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
RAFIQ
  • 905
  • 3
  • 18
  • 32

3 Answers3

11

To skip the first 4 lines (and therefore start from the 5th):

tail --lines=+5 script.sh | sh

According to the man page, --lines=K means output the last K lines, instead of the last 10; or use -n +K to output starting with the Kth.

Credit goes to Aaron Digulla for his answer here. EDIT: Thanks to l0b0 for preventing my cat from taking over the world!

Community
  • 1
  • 1
Bardi Harborow
  • 1,803
  • 1
  • 28
  • 41
  • UUOC: Just use `tail --lines=+4 script.sh`. – l0b0 Apr 09 '15 at 13:48
  • thanks, thats great, was wondering if there is some flag or any simpler way not too different from running script again, will not require to document long commands, in your comment did you mean N lines?. – RAFIQ Apr 09 '15 at 13:52
  • there is a problem with this if script fails second time it will return line numbers starting from 1 with partial script that we are running so we need to add first error line and new failed line number to actually resume from second failure – RAFIQ Apr 09 '15 at 13:57
1

When you think you often have to do something like this, you can use a special variable. And make an optional commandline parameter (default start at the beginning) that tells you where to start.
The unstructured version would look like:

#!/bin/sh
if [ $# -eq 1 ]; then
   PHASE=$1
else
   PHASE=1
fi
echo phase $PHASE

if [ ${PHASE} -eq 1 ]; then
        echo "install 1"
        (( PHASE = PHASE + 1 ))
fi

if [ ${PHASE} -eq 2 ]; then
        echo "install 2"
        [ $? -eq 0 ] || exit $?;
        (( PHASE = PHASE + 1 ))
fi

if [ ${PHASE} -eq 3 ]; then
        echo cyberciti
[ $? -eq 0 ] || exit $?;
        # Still phase 3, cyberciti is not a special phase

        echo "install 3"
        (( PHASE = PHASE + 1 ))
fi

if [ ${PHASE} -eq 4 ]; then
        echo "install 4"
        (( PHASE = PHASE + 1 ))
fi

An improvement would be using a while loop:

#!/bin/sh
if [ $# -eq 1 ]; then
   PHASE=$1
else
   PHASE=1
fi

function phase2 {
        echo "install 2"
        [ $? -eq 0 ] || exit $?;
}

function phase3 {
        echo cyberciti
        [ $? -eq 0 ] || exit $?;
        # Still phase 3, cyberciti is not a special phase
        echo "install 3"
}

while [ ${PHASE} -lt 5 ]; do
        [ ${PHASE} -eq 1 ] && echo "install 1"
        [ ${PHASE} -eq 2 ] && phase2
        [ ${PHASE} -eq 3 ] && phase3
        [ ${PHASE} -eq 4 ] && echo "install 4"
        (( PHASE = PHASE + 1 ))
done

Further improvements might include logical names and some special flow control that can be altered within a phase.

EDIT: Improvement using case-construction

#!/bin/sh
if [ $# -eq 1 ]; then
   PHASE=$1
else
   PHASE=1
fi

function phase2 {
        echo "install 2"
        [ $? -eq 0 ] || exit $?;
}

function phase3 {
        echo cyberciti
        [ $? -eq 0 ] || exit $?;
        # Still phase 3, cyberciti is not a special phase
        echo "install 3"
}

endloop=false
while [ ${endloop} = false ]; do
   case ${PHASE} in
       1) echo "install 1" ;;
       2) phase2 ;;
       3) phase3 ;;
       4) echo "install 4" ;;
       5) endloop=true ;;
       *) echo "Phase ${PHASE} not supported" ;;
    esac
    (( PHASE = PHASE + 1 ))
done
Walter A
  • 19,067
  • 2
  • 23
  • 43
0
#!/bin/sh
if [ $# -eq 1 ]; then
 PHASE=$1
else
 PHASE=1
fi
if [ ${PHASE} -le 6 ]; then
    echo "install 1 "
    echo "install 2 "
fi
if [ ${PHASE} -le 10 ]; then
  cyberciti
  [ $? -eq 0 ] || exit $?;
  echo "install 3 "
  [ $? -eq 0 ] || exit $?;
fi
if [ ${PHASE} -le 16 ]; then
    echo "install 4"
    [ $? -eq 0 ] || exit $?;
fi

This is the final script i needed which when we first run (sh test.sh)will fail at cyberciti, then we will need only to run from this line after replacing cyberciti with valid command, so it resumes running from this line by with new argument as error line (sh test.sh 11)

RAFIQ
  • 905
  • 3
  • 18
  • 32