Help with if statement syntax in shell script

I want to make the file test condition a variable ($Prmshn in code below).
My goal is to use something like the first three unsuccessful if statetments since the 'if [[' is the newer style. Note: I copied the error message to the right of each of the three unsuccessful if statements.

 
#!/bin/ksh
test_input()
{
Prmshn=${1}
InFLNm=${2}
ifReq="-$Prmshn $InFLNm"
#the following three if statments fail:
#if [[ -${Prmshn} ${InFLNm} ]] ; then    #/testing/test.ksh: syntax error at line 8 : `${InFLNm}' unexpected
#if [[ $ifReq ]] ; then     #/testing/test.ksh: syntax error at line 9 : `]]' unexpected
#if [[ "$ifReq" ]] ; then     #/testing/test.ksh: syntax error at line 10 : `]]' unexpected
#the following six if statments are successful:
#if [ "$ifReq" ] ; then
#if [[ -r /input/test.txt ]] ; then
#if [[ -r $InFLNm ]] ; then
#if test -r $InFLNm ; then
#if test -$Prmshn $InFLNm ; then
if test $ifReq ; then
# each of the previous if statements were used in turn with the balance of the statement following:
  echo "input file is now available."
else
  echo "input file is not available."
fi
}
test_input r /input/test.txt

You are setting a variable to start with the character "-".
Why are you expceting this to return true?

What are you expecting the user to pass?

Suggestion:
When labeling a variable like 'if', 'is', 'be' or 'do'-XY, i recomend that the variable is actualy a boolean.
So, when setting the variable, you take care that only a return value is stored, so you can check (use IF) it like you did.

Anyhow, for if blocks, i do not recomend 'test', though that is only personal preference, but to me the following are the same and tend to be most effective:

beBool=false

$beBool || echo "successfully failed"

[[ false = $beBool ]] && echo "successfully failed"

if [ false = $beBool ]
then  echo "failed"
else  echo "success"
fi

if ! $beBool
then  echo "failed"
else  echo "success"
fi

Hope this helps

You may want to execute your script with the -v and/or -x option set to see what the shell actually does.

sea -
I was hoping that one of these if statements:

if [[ -${Prmshn} ${InFLNm} ]] ; then
if [[ $ifReq ]] ; then
if [[ "$ifReq" ]] ; then

would resolve to:

if [[ -r /input/test.txt ]] ; then

RudiC-
I changed the condition from r to v and received the same syntax error messages.

All -
this statement works:

if [ "$ifReq" ] ; then

however this statement does not work:

if [[ "$ifReq" ]] ; then

---------- Post updated at 11:57 AM ---------- Previous update was at 11:42 AM ----------

I should clarify that the permissions on the file that my condition test is examining are:

-rwxrwxr-x /input/test.txt

Ahhh i guess i understand (partly) what you want...

-${Prmshn} does NOT expand to: -P, -r, -m, -s, -h, -n
It expands to -'content_of_variable_Prmshn' , which actualy is just what you passed as first argument $1 .

As suggested by Rudi, execute your script with either -v or -x .

sh -x myscript.sh

Hope this helps

sea/RudiC - if i understand your suggestion correctly, i have called the test_input function with a -x parameter.
i still had similar results with the -x not resolving for the newist form of if statement (using the [[) however the -x resolves ok with the older forms of if statements (using [ and also test):

 
#!/bin/ksh
test_input()
{
Prmshn=${1}
InFLNm=${2}
# the following if stmt does not work (err msg to the right):
#if [[ ${Prmshn} ${InFLNm} ]] ; then    # syntax error at line 7 : `${InFLNm}' unexpected
# the two following if stmts work ok:
#if [ "$Prmshn" "$InFLNm" ] ; then
if test "$Prmshn" "$InFLNm" ; then
  echo "$InFLNm input file is now available."
else
  echo "$InFLNm input file is not available."
fi
}
test_input -x /input/test.txt

The '-x' is not chaning anything of how it executes.
It just prints it before, so you have a way to see and check if the script does what it should.
As in, are there variables, and if there are, are they the right ones, and so on...

Write:

echo "DEBUG: $Prmshn -- $InFLNm" 

above

if test "$Prmshn" "$InFLNm" 

and run the script without '-x' and post its output please.

There are huge differences between ksh (and bash ) test expression and [ expression ] versus [[ expression ]] .

The test and [ are the names of utilities (usually the same physical utility and almost always implemented as shell built-ins). But [[ and ]] are keywords in the Korn shell's grammar; not commands to be invoked.

In the following examples, assume that a script starts with:

#!/bin/ksh
op="-$1"
file="$2"
exp="$op $file"

(similar to what you had in your initial post), and continues with the commands included in the examples.

Example 1:
The commands:

if test "$exp";then echo true;else echo false;fi
if [ "$exp" ];then echo true;else echo false;fi

will both ALWAYS print true . Since the expansion of $exp is quoted, a single string is being passed to test . Therefore, this will test whether or not $exp expands to an empty string. Since it contains at least two characters, it is not an empty string. Therefore, it evaluates to true. These commands are logically treated as identical to the commands:

if test -n "$exp";then echo true;else echo false;fi
if [ -n "$exp" ];then echo true;else echo false;fi

Example 2:
Without the quotes:

if test $exp;then echo true;else echo false;fi
if [ $exp ];then echo true;else echo false;fi

will evaluate the operation specified by $op against the file specified by $file . As long as there aren't any IFS characters in the expansions of $op and $file , and <space> is included in IFS (so field splitting will separate $op and $file into separate arguments to test ) this should do what you want.

Example 3:
If a filename contains any IFS characters, the code in Example 2 won't work, but the commands:

if test "$op" "$file";then echo true;else echo false;fi
if [ "$op" "$file" ];then echo true;else echo false;fi

will do what you want for any valid test op code.

Example 4:
The commands:

if [[ $op $file ]];then echo true;else echo false;fi
if [[ "$op" $file ]];then echo true;else echo false;fi
if [[ $op "$file" ]];then echo true;else echo false;fi
if [[ "$op" "$file" ]];then echo true;else echo false;fi

are all equivalent and will always give you a syntax error. Since [[ is a keyword (not the name of a utility), the shell itself recognizes that $op and $file are variables and doesn't perform field splitting or pathname expansion. Neither ksh nor bash accept a variable as an operator in the expression evaluated by [[ expression ]] and two variables can't be concatenated without an operator between them. So, you get a syntax error.

Example 5:
Since [[ doesn't do field splitting, the commands:

if [[ $exp ]];then echo true;else echo false;fi
if [[ "$exp" ]];then echo true;else echo false;fi

are treated as equivalent to:

if [[ -n "$exp" ]];then echo true;else echo false;fi

as in Example 1 above.

With sea's suggestion of using set -x (either using that as the 2nd line in your script, or by invoking your script with):

ksh -x script_name operator pathname

you'll be able to see how ksh handles each of these examples.

5 Likes

my ultimate goal is to have a file test in a function with the test condition and file name fed in as parameters.
i placed the echo statement just before the test statement.

#!/bin/ksh
test_input()
{
Prmshn=${1}
InFLNm=${2}
echo "DEBUG: $Prmshn -- $InFLNm"
if test "$Prmshn" "$InFLNm" ; then
  echo "$Prmshn $InFLNm input file is now available."
else
  echo "$Prmshn $InFLNm input file is not available."
fi
}
#test_input -x /input/test.txt
test_input /input/test.txt

when i kept the -x in the function call i got this:
DEBUG: -x -- /input/test.txt
when i removed the -x from the function call, as suggested i got this message:
/scripts/testing/mks.ksh: test: argum/input/test.txt input file is not available.

Don't use -x as a function parameter; run the set -x command to set this option (c.f. man ksh ) It will print every command line after expansion.

Huh? Who suggested that you remove one of the two required parameters to your function?

There was a suggestion that you could invoke your script with:

ksh -x /scripts/testing/mks.ksh

to turn on tracing. And there was a suggestion that you could change your script to:

#!/bin/ksh
set -x
test_input()
{
Prmshn=${1}
InFLNm=${2}
echo "DEBUG: $Prmshn -- $InFLNm"
if test "$Prmshn" "$InFLNm" ; then
  echo " $Prmshn $InFLNm input file is now available."
else
  echo " $Prmshn $InFLNm input file is not available."
fi
}
test_input -x /input/test.txt

to enable tracing. Or, to make it easier to read and enable tracing, something like:

#!/bin/ksh
set -x
test_input() {
	Prmshn=${1}
	InFLNm=${2}
	echo "DEBUG: $Prmshn -- $InFLNm"
	if test "$Prmshn" "$InFLNm"
	then	echo " $Prmshn $InFLNm input file is now available."
	else	echo " $Prmshn $InFLNm input file is not available."
	fi
}
test_input -x /input/test.txt

NOTE: I added a space in your echo commands before $Prmshn . Calling echo with a 1st argument that starts with a minus sign produces results that vary radically from system to system!

Using:

test_input -x /input/test.txt

as the last line in your script is a asking your function to determine whether or not /input/test.txt is an executable file. If you just want to know whether or not /input/test.txt is present on your system, use:

test_input -e /input/test.txt

If you want to know if /input/test.txt is present and is a regular file, use:

test_input -f /input/test.txt

If you want to know if /input/test.txt is present and is a directory, use:

test_input -d /input/test.txt

If you want to know if /input/test.txt is present and is readable, use:

test_input -r /input/test.txt