2

I am trying to write a simple script with the following logic: IF the first argument is a valid regular file, run the for-loop; if no argument is provided, run "code2"; all else, run "code3". The following script seems Okay to me, but it got stuck if run without an argument.

#!/bin/bash

if [ -f $1 ]; then
  for i in `cat $1`
  do
    <something>
  done
elif [ $# -eq 0 ]; then
  "code2"
else
  "code3"
fi

Here is the debug output and it got stuck at the end.

bash -x myscript
+ '[' -f ']'
++ cat

Since I provide no argument, why does it still run into the first if-then flow? I am new to bash scripting. Any help would be thankful.

2 Answers 2

3

If you do not quote the variable "$1" then it becomes nothing and disappears. The code executed is then (as reported by the shell -x option):

[ -f ]

Which, as -f is an string with a length of not zero results in a true test and runs the then part.

You need to write (at least):

[ -f "$1" ]

Which, with an empty argument, will become

[ -f "" ]

and report a failure to match the "" file.

One other alternative is to use a parameter expansion (no external quoting needed):

[ -f ${1:-""} ]

It will expand to "" if the value of $1 is null or empty.

And please do not do a for loop to walk the lines of a file. You should consider using a while read loop

#!/bin/sh

if [ -f ${1:-""} ]; then
  while read -r line; do
      echo '<something>'
  done <"$1"
elif [ "$#" -eq 0 ]; then
  echo "code2"
else
  echo "code3"
fi
0
0

Simple answer is because with non-existent $1, which is also not quoted ( also part of the problem ) the shell treats expression as [ -f ] and the -f that [ sees here isn't recognized as flag, but just a single "expression". It's in fact same as:

$ [ abracadabra  ] && echo "success"
success

And to quote test manual (which in case you didn't know is alias for [ ):

   An  omitted  EXPRESSION  defaults  to false.  Otherwise, EXPRESSION is true or false and sets exit
   status.  It is one of:

   ( EXPRESSION )
          EXPRESSION is true

Note that if you did quote the expression it would look like so when tracing the output, i.e. it would in fact try to evaluate a null string as existing filename:

$ (set -x; [ -f "$this_var_doesnt_exist"  ] && echo "hi" )
+ '[' -f '' ']'
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .