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
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
./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 .
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 ...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.