1

I have been stuck on an issue for a couple of hours now regarding bash shell arrays.

I am using an array of strings created from an inputFile using IFS=$'\n' as the separator.

Each index of the array may contain multiple words separated by spaces. Each string represents a combination of Options/Arguments that may be used with the execution of another shell script.

I attempt to supply the these strings to the other shell script I wrote using variations of the following syntax:

    # Run the testcases, case by case
    for testcase in `cat $inputFile` ###"${testcases[@]}"
    #for ((i = 0; i < ${#testcases[@]}; i++))
            do
                    #testcase="${testcases[i]}"
                    # Print each case in inputFile
                    echo "${testcase}"

                    # Run the Archive Script, redirect output to /dev/null
                    ./archive.sh "${testcase}" > /dev/null

    # Respond to $# return value

done

You will notice a few different variations I have used to loop through an array (or attempt to directly respond by directly reading into a local variable from the output of cat.

What is most frustrating is that the echo command works, and prints the string with spaces. However, when my script attempts to execute using the string, the first word is read as a whole but following the first space, the script attempts to execute the script a single character at a time. :(

Please help! Here is the output I get when executing the script:

$ test_archive.sh lab6_testcase
Testcases Count: 6
Running cases:
-v dirA
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
dirB
-v -r dirA
./archive.sh: illegal option --  
./archive.sh: illegal option -- -
./archive.sh: illegal option -- r
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
-v dirA dirB
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- B
dirc
-a
./archive.sh: illegal option -- a
TEST SUMMARY
SUCCESSFUL CASES:0
USAGE CASES:0
INVALID ARGUMENT CASES:6
-v dirA
dirB
-v -r dirA
-v dirA dirB
dirc
-a

Here is the Full Script incase I have missed some key line triggering and error:

#!/bin/bash
# CONSTANTS
SUCCESS=0
USAGE_ERROR=1
INVALID_ARGUMENT=2

# Set the Input Field Seperator to '\n'
IFS=$'\n'

# Setup counters
usageErrorCount=0
argumentErrorCount=0
successCount=0

# Check if not enough or too many arguments have bee supplied
if (( $# != 1 ))
then
   echo Usage: $0 filename
   exit $USAGE_ERROR
fi

# Store the File in inputFile
inputFile=$1

# Check if the inputFile exists
if [[ ! -f $inputFile ]]
then
        # Report that the file does not exist
        echo "Exiting: The input file '$inputFile' does not exist!"
        exit $INVALID_ARGUMENT
fi

# Read the lines from the file, and place them in the array
testcases=( `cat $inputFile` )

echo Testcases Count: ${#testcases[@]}


# Inform use of case list
echo Running cases:

# Run the testcases, case by case
for testcase in `cat $inputFile` ###"${testcases[@]}"
#for ((i = 0; i < ${#testcases[@]}; i++))
        do
                #testcase="${testcases[i]}"
                # Print each case in inputFile
                echo "${testcase}"

                # Run the Archive Script, redirect output to /dev/null
                ./archive.sh "${testcase}" > /dev/null

                # Use Switch Statement on ENV Success Var (#?) to:
                        # 1. Increment counters
                        # 2. Add testcase to appropriate array
                case $? in
                        $USAGE_ERROR)           # Add testcase to usage array
                                                                usageCases[$usageErrorCount]="$testcase"
                                                                # Up Usage Count
                                                                usageErrorCount=$((usageErrorCount+1))

                        ;;
                        $INVALID_ARGUMENT)      # Add testcase to argument array
                                                                argumentCases[$argumentErrorCount]="$testcase"
                                                                # Up Argument Count
                                                                argumentErrorCount=$((argumentErrorCount+1))

                        ;;
                        $INVALID_ARGUMENT)      # Add testcase to success array
                                                                successCases[$successCount]="$testcase"
                                                                # Up Success Count
                                                                successCount=$(($successCount+1))
                        ;;
                        esac
        done

# Format the Output
echo "TEST SUMMARY"

# Report Successful Cases
echo "SUCCESSFUL CASES:$successCount"
for testcase in  ${successCases[@]}
        do
                echo $testcase
        done

# Report Ussage Cases
echo "USAGE CASES:$usageErrorCount"
for testcase in  ${usageCases[@]}
        do
                echo $testcase
        done

# Report Successful Cases
echo "INVALID ARGUMENT CASES:$argumentErrorCount"
for testcase in  ${argumentCases[@]}
        do
                echo $testcase
        done

# Exit with Success
exit $SUCCESS
2
  • Do you double quote the parameter in archive.sh, too? Commented May 19, 2015 at 9:00
  • for testcase in cat $inputFile is BEST avoided. use while loop instead. Commented May 19, 2015 at 9:28

3 Answers 3

2

I found a solution to the issue after some digging.

The issue is that the shell executes the command before evaluating/dereferencing the contents of the variable (or array value).

Because of this, eval must be used to force the shell to dereference the variable/array and retrieve the contents before executing the command proceeding the variable/array.

Here is a working version (reading directly from file):

for testcase in `cat $inputFile`
        do
                #testcase="${testcases[i]}"
                # Print each case in inputFile
                echo "  ${testcase}"

                # Run the Archive Script, redirect output to /dev/null
                eval ./lab5.sh ${testcase} > /dev/null

... CONTINUE WITH SCRIPT ...
Sign up to request clarification or add additional context in comments.

Comments

1

The problem is due to your IFS still being set to $'\n' so ./archive.sh is reading the whole line as a single argument and trying to make sense of the letters.

Change the IFS back to ' ' and the problem should be gone!

Example:

    # Run the testcases, case by case
    for testcase in "${testcases[@]}"
            do
                    IFS=' '
                    echo "${testcase}"

                    ./archive.sh "${testcase}" > /dev/null

done

2 Comments

Probably need to both change IFS and remove quotes.
This seems to be very close to the solution. It has eliminated the errors, but is now running each spaced word as an individual case.
0
 ./archive.sh "${testcase}"

You are calling archive.sh with a single argument (with embedded whitespace). That's what double quotes do. Everything inside double quotes is a single word.

Since the first character of the argument is a dash, archive.sh takes the rest of the argument (including the embedded space) as options, and complain about them not being valid options.

You want to drop the quotes. Demo.

2 Comments

without the quotes I still get the same output...though what you are saying makes conceptual sense.
It's hard to tell what exactly is missing. Simplify your script to the point you can demo it e.g. on ideone.com.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.