#!/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?
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! 
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With