RAFIQ RAFIQ - 2 months ago 7
Bash Question

How to start a shell script from a specific line?

#!/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?

Answer

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