Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start a shell script from a specific line?

Tags:

linux

shell

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

like image 933
RAFIQ Avatar asked Oct 28 '25 05:10

RAFIQ


2 Answers

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!

like image 141
Bardi Harborow Avatar answered Oct 30 '25 21:10

Bardi Harborow


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
like image 31
Walter A Avatar answered Oct 30 '25 21:10

Walter A



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!