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

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

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 '' ']'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.