Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

I am trying to write a function like the one above and place it in my .bashrc file. After I source the file and run, I get:

Total time: 51 seconds
-bash: [1: command not found
OK!

Can someone help me understand what I did wrong?

share|improve this question
4  
Testing if $? is equal to 0 with an if statement is pointless, if expects a command and if said command returns 0, it runs the code in the block. so if true; then echo hello; fi will echo hello since the command true returned 0. –  llua Feb 4 at 22:18
1  
@llua It's not pointless. $? holds the status of the last pipeline, which is not the test ([) command in the if statement. The example is testing whether some command was successful. You can do the same with && and ||, but it can make long, unreadable lines compared to if [ $? -eq 0 ]. The same argument goes for if some command –  bonsaiviking Feb 5 at 17:03
    
@bonsaiviking I am well aware of what $? expands to, i am pointing out there is no point in the test being used; since if some command does the same thing with one statement versus having two separate statements. if the command is already long, adding three more characters wouldn't make the 'unreadable' terribly more 'unreadable'. –  llua Feb 5 at 18:25

5 Answers 5

up vote 26 down vote accepted

Add a space after the [, and another before ]:

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[ is a shell builtin, it is a command just like echo, read, expr... it needs a space after it, and requires a matching ].

Writing [ $? -ne 0 ] is actually invoking [ and giving it 4 parameters: $?, -ne, 0, and ].

Note: the fact that you are getting an error saying [1: command not found means that $? was having the value of 1.

share|improve this answer
1  
I just verified that your answer is correct on my Linux VM. –  samiam Feb 4 at 22:14
    
[ is a link to test as well –  Ricky Beam Feb 5 at 1:15
2  
@RickyBeam in most shells, [ is a shell builtin, and the /usr/bin/[ is rarely used. –  Patrick Feb 5 at 13:23

Or you could skip $? altogether. If your command is cmd, the following should work:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}
share|improve this answer

It's good practice to assign the return value to a variable before using it

retval="$?"
if [ $retval -ne 0 ]

It allows you to reuse the return value. e.g. in an if... elif... else... statement.

share|improve this answer
    
-1: You forgot the space after [ (Without the space, it becomes a syntax error in bash) Will undo if you edit and fix your error. –  samiam Feb 4 at 22:15
    
Yep, you're right. I fixed it. –  Abdul Feb 4 at 22:15
    
@samiam that last comment was directed at you –  terdon Feb 4 at 22:16
4  
:) Could you expand your answer a bit. Why is it good practice? What kind of errors could be avoided? –  terdon Feb 4 at 22:19
1  
@terdon it's bad practice to use $? directly because that will break if you ever, when editing the script later, put a line between the command and the $? check. –  samiam Feb 4 at 22:21

The only reason why you'd want to use $? as arguments to a [ command (whether that [ command is run in the condition part of an if statement or not) is when you want to discriminate on a specific return status, like:

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

The syntax for all those if, while, until... statements is

if cmd-list1
then cmd-list2
else cmd-list3
fi

Which runs cmd-list2 if cmd-list1 is successful or cmd-list3 otherwise.

The [ "$?" -eq 0 ] command is a no-op. It sets $? to 0 if $? is 0, and $? to non-zero if it was non-zero.

If you want run something if cmd failed, it's:

if ! cmd
then ...
fi

Generally, you don't need to tinker with $? let alone know which value means true or false. The only cases are as I said above if you need to discriminate on a specific value, or if you need to save it for later (for instance to return it as the return value of a function) like:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

Also remember that leaving a variable unquoted is the split+glob operator. It doesn't make sense to invoke that operator here, so it should be:

[ "$?" -ne 0 ]

not [ $? -ne 0 ], let alone [$? -ne 0 ] (which would only invoke the [ command if $IFS happened to contain the first character of $?).

Also note that the Bourne way to define a function is to stick function-name() in front of a command. That's the case in every Bourne like shell except bash and yash (and recent versions of posh) which only allow a compound command (compound commands being {...} or (...) or things like for...done, if...fi...

function foo { ... } is the ksh function definition syntax. There's no reason why you'd want to use it here.

Your code can be portably (POSIXly) written:

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

Also note that cd without -P has a very special meaning (handles paths that contain .. components differently from any other command), so it's better to include it in scripts to avoid confusions.

(that function returns false if cd fails, but not if <some command> fails).

share|improve this answer

I do believe the command below will do everything you want in one line.

(( verify = $?!=0?'Nope!':'OK!' ))
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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