1

I have written a script for the purpose of calling it from other scripts and am having issues doing so.

The script I wish to call from other scripts works correctly:

#!/bin/bash

####################################################################################################
# This script will compare two directories given as args.
#
# exit status: 0 --> if directories are the same
#              1 --> if directories are not the same
#              2 --> incorrect number of args
#              3 --> one or more of the directories does not have read permissions
#              4 --> one or more of the directories does not exists
#              5 --> one or more of the directories is not a directory
####################################################################################################


[ $# -ne 2 ] && exit 2

[ ! -r "$1" ] || [ ! -r "$2" ] && exit 3
[ ! -e "$1" ] || [ ! -e "$2" ] && exit 4
[ ! -d "$1" ] || [ ! -d "$2" ] && exit 5

dir_1="$1"
dir_2="$2"
sha1_dir_1=$(find "$dir_1" -type f \( -exec sha1sum {} \; \) | awk '{print $1}' | sort | sha1sum)
sha1_dir_2=$(find "$dir_2" -type f \( -exec sha1sum {} \; \) | awk '{print $1}' | sort | sha1sum)

[ "$sha1_dir_1" = "$sha1_dir_2" ] && exit 0
[ "$sha1_dir_1" != "$sha1_dir_2" ] && exit 1

I have tested it by calling it from the command line. Below is a test script which I cannot seem to call the above script from successfully:

#!/bin/bash

dir_1="~/test"
dir_2="~/test1"
directories_are_same="$(~/bin/compare_directories "$dir_1" "$dir_2")"

{
    if [ $directories_are_same -eq 3 ]; then
        echo "One of the directories $dir_1 and $dir_2 does not have read permissions!"
        exit 1
    elif [ $directories_are_same -eq 4 ]; then 
        echo "One of the directories $dir_1 and $dir_2 does not exist!"
        exit 1
    elif [ $directories_are_same -eq 5 ]; then
        echo "One of the directories $dir_1 and $dir_2 is not a directory!"
        exit 1
    fi
} >&2

if [ $directories_are_same -eq 0 ]; then
    echo "The directories $dir_1 and $dir_2 contain identical content"
    exit 0
elif [ $directories_are_same -eq 1 ]; then
    echo "The directories $dir_1 and $dir_2 do not contain identical content"
    exit 0
else
    echo "Something went wrong" >&2
    exit 1
fi

The output from the test script I am getting is:

/home/astral/bin/updates_dir_if: line 8: [: -eq: unary operator expected
/home/astral/bin/updates_dir_if: line 11: [: -eq: unary operator expected
/home/astral/bin/updates_dir_if: line 14: [: -eq: unary operator expected
/home/astral/bin/updates_dir_if: line 20: [: -eq: unary operator expected
/home/astral/bin/updates_dir_if: line 23: [: -eq: unary operator expected
Something went wrong

I have tried using the full path to the script, the relative path from the test script which would be ./, and the way that it currently is ~/bin/scriptname. All give the same results.

I have read some posts which seem to imply that what I am doing should work, such as:

StackOverflow post

Quote your args in Testscript 1:

echo "TestScript1 Arguments:"
echo "$1"
echo "$2"
echo "$#"
./testscript2 "$1" "$2"

What am I doing incorrectly?

13
  • 1
    Run your calling script with bash -x yourscript Commented Feb 24, 2021 at 15:41
  • 1
    Related question regarding function output vs. exit status: Returning value from called function in a shell script Commented Feb 24, 2021 at 15:56
  • 1
    @AstralAxiom : That a script runs fine from the command line, does not mean it runs well from another context. Scripts can be sensitive to environment, working directory and so on. In addition, a possible bug is that you did not quote $directories_are_same. While it may work if everything goes well, it really depends on the correct output of compare_directories in your case, and quoting it would mean one thing less which you have to worry. Commented Feb 25, 2021 at 8:41
  • 1
    I don't understand why you are catching the stdout of compare_directories. Actually, the result of the comparision is communicated to the caller via the exit code, not stdout. Commented Feb 26, 2021 at 8:02
  • 1
    @AstralAxiom : I now see that you reflected this in your own answer already. In this case, the quotes around $? and $directories_are_same are of course unnecessary, but they don't harm. Commented Feb 26, 2021 at 8:11

1 Answer 1

1

I figured it out. The exit status is what I need, so I need to call it and set the variable to the exit status stored in $?. The issue is that I was catching the stdout of the other script and storing it in the variable directories_are_same as if it were a return value that I was expecting, when what I needed was its exit status. I could echo something from the other script and then treat the stdout as a returned string, but that is not how this script was designed.

Here is the working test script:

#!/bin/bash

dir_1=~/test
dir_2=~/test1
~/bin/compare_directories "$dir_1" "$dir_2"
directories_are_same="$?"

{
    if [ "$directories_are_same" -eq 3 ]; then
        echo "One of the directories $dir_1 and $dir_2 does not have read permissions!"
        exit 1
    elif [ "$directories_are_same" -eq 4 ]; then 
        echo "One of the directories $dir_1 and $dir_2 does not exist!"
        exit 1
    elif [ "$directories_are_same" -eq 5 ]; then
        echo "One of the directories $dir_1 and $dir_2 is not a directory!"
        exit 1
    fi
} >&2

if [ "$directories_are_same" -eq 0 ]; then
    echo "The directories $dir_1 and $dir_2 contain identical content"
    exit 0
elif [ "$directories_are_same" -eq 1 ]; then
    echo "The directories $dir_1 and $dir_2 do not contain identical content"
    exit 0
else
    echo "Something went wrong" >&2
    exit 1
fi

Now when the directories are different I get:

The directories /home/astral/test and /home/astral/test1 do not contain identical content

and when they are the same I get:

The directories /home/astral/test and /home/astral/test1 contain identical content
Sign up to request clarification or add additional context in comments.

4 Comments

A full path path is probably not required. "~/test" does not work because you quoted it and bash interprets the quoted ~ literally (meaning, this isn't your home directory but a directory named literally ~). dir_1=~/test should work too (note the missing quotes).
Instead of updating your answer by appending new information, you should re-write it as if you knew everything already – the history is preserved in the edit history.
OK, thanks! I did not want to take the credit when I was not the one who noticed that : )
@AstralAxiom : Bash is not a programming language, it is a scripting language. A scripting language is a programming language. At least bash is Turing complete

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.