Ubuntu – exit a bash command in a script without exiting the script

bashscripts

I am working on a script that looks at a homework folder (the source files) and if the folder exists, it then looks for a destination folder. If that folder does not exist, it copies the source to the destination.

If the destination exists, it attempts to copy the file from the source to the destination and before doing so, prompt the user first so that it doesn't overwrite work already done by that user.

The output of the command must be in a specific format so I cannot use the standard output of the command as is. I must capture it and reformat it. Then take input (i.e. y/N) in a specific format.

The benefit of doing this, is that the copy command already does things that are helpful. If a file does not exist, it does the copy.

If a file, or several files already exist, it will repeatedly ask "overwrite y/n?" It is this case, that I'm trying to deal with.

I've made it as far as capturing the output of the copy command into a variable and suppressing its normal output so that I can reformat its output and echo that format back to the user.

Next, my thinking is that I need to kill (or otherwise stop the command somehow), then print the output in the my desired format and then re-invoke the command and on the second time, I can echo the y/N prompt in my desired format and the user can then make their choice. Despite searching, I have not been able to figure out/understand how to kill or otherwise stop the command once it is invoked. I've tried kill and various attempts at using SIGINT. Either I just don't understand how to use these, or they are not the right choice. When I try to use them, I get syntax error.

Here is my code:

#!/bin/bash

USAGE="Usage: ./script2.sh [hw-name]"
EINVALID="Invalid homework: $1"
SOURCEDIRECTORY="$PUBLIC/homework/$1"
HOMEWORKDIRECTORY="$HOME/homework/$1"
COPY="$SOURCEDIRECTORY/*.*"

if [ -z "$1" ]; then
    echo $USAGE
    exit
fi

if [ ! -d "$SOURCEDIRECTORY" ]; then
    echo $EINVALID
    exit
fi

if [ ! -d "$HOMEWORKDIRECTORY" ]; then
    echo "making homework1"
    mkdir -p $HOMEWORKDIRECTORY

copyOutput2="$(eval cp -ir $COPY $HOMEWORKDIRECTORY 2>&1 &stop this
 process somehow)"
echo $copyOutput2 #temporary output for testing

Best Answer

If one really really really needs to have custom cp with custom message, then recompiling the program from source is the way to go, but a bit more sensible approach would be to write out your own message via printf preferably, instead of trying to intercept cp's output, and handle user choices via select dialog. Additionally, if you're going to output error messages, they should go to stderr stream. Finally, *.* is unnecessary and you can just use * glob instead.

Below is the script with a couple edits. Note that you need to uncomment #cp "$item" "$HOMEWORKDIRECTORY" line for the actual copying to occur. For testing purposes replace cp with echo first.

#!/bin/bash

USAGE="Usage: ./script2.sh [hw-name]"
EINVALID="Invalid homework: $1"
SOURCEDIRECTORY="$PUBLIC/homework/$1"
HOMEWORKDIRECTORY="$HOME/homework/$1"
#COPY="$SOURCEDIRECTORY/*.*"

if [ -z "$1" ]; then
    echo "$USAGE" > /dev/stderr
    exit 1
fi

if [ ! -d "$SOURCEDIRECTORY" ]; then
    echo "$EINVALID" > /dev/stderr
    exit 2
fi

if [ ! -d "$HOMEWORKDIRECTORY" ]; then
    echo "making homework1"
    mkdir -p $HOMEWORKDIRECTORY

for item in "$SOURCEDIRECTORY"/*; do
    skip=true
    if [ -f "$HOMEWORKDIRECTORY"/"${item##*/}" ]; then
        printf "%s already exists in %s.\n" "$item" "$HOMEWORKDIRECTORY"

        select choice in  "overwrite" "skip"; do
            case "$choice" in 
                "overwrite")  echo "Overwriting."  
                              break;;
                "skip") skip=true; break;;
            esac
        done
    fi

    if [ "$skip" = "true" ]; then
        continue
    fi
    echo cp "$item" "$HOMEWORKDIRECTORY"

done
Related Question