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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I get what I expected when doing this in bash:

[ "a" == "a" ] && echo yes

It gave me yes.

But when I do this in zsh, I get the following:

zsh: = not found

Why does the same command (/usr/bin/[) behave differently in different shells?

share|improve this question
5  
it's not the same command - its a builtin found before $PATH is searched. and == isn't valid test syntax for the /usr/bin/[ anway. Just = is fine. – mikeserv Jan 15 at 8:46
up vote 16 down vote accepted

It's not /usr/bin/[ in either of the shells. In Bash, you're using the built-in test/[ command, and similarly in zsh.

The difference is that zsh also has an = expansion: =foo expands to the path to the foo executable. That means == is treated as trying to find a command called = in your PATH. Since that command doesn't exist, you get the error

zsh: = not found

that you saw (and in fact, this same thing would happen even if you actually were using /usr/bin/[).


You can use == here if you really want. This works as you expected in zsh:

[ "a" "==" "a" ] && echo yes

because the quoting prevents =word expansion running. You could also disable the equals option with setopt noequals.


However, you'd be better off either:

  • Using single =, the POSIX-compatible equality test; or
  • Better still, using the [[ conditionals with == in both Bash and zsh. In general, [[ is just better and safer all around, including avoiding this kind of issue (and others) by having special parsing rules inside.
share|improve this answer
    
What's the exact difference between [ and [[? (Searching on Google for [ vs [[ gives me results for vs only, LOL) – Johnson Steward Jan 15 at 9:04
2  
[[ supports a wider range of tests in both cases, and has custom parsing rules that avoid the need for quoting variables, operators, and so on. If you're specifically using either Bash or zsh, use [[. If you're writing a portable script, write to the POSIX-compatible [/test command (which may or may not be a real command on your running system). – Michael Homer Jan 15 at 9:06
    
i'm doing this inside my zshrc for exporting $TERM when using xfce4-terminal (replacing xterm to xterm-256color) – Johnson Steward Jan 15 at 9:09
1  
Just use [[ there and forget [ exists. – Michael Homer Jan 15 at 9:09
2  
Well, =/== is arguably one case where [[ is not better than [, as [[ a == b ]] is does "a" match the "b" pattern and not is "a" equal to "b" as you'd expect. That means you need to write [[ $a == "$b" ]] for instance. At least, with the [ command, if you know how command parsing works, you know you need to write it [ "$a" = "$b" ] to prevent the split+glob operator like in other commands. With that in mind and if you don't use -a or -o, [ is safe in POSIX conformant implementations. – Stéphane Chazelas Jan 15 at 10:07

And zsh, and bash give the same answer (type is builtin too for both shells):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
share|improve this answer

In both shells, bash and zsh, the [ utility is a shell builtin. This is the shells implementation of that tool, it is used in preference to the binary /usr/bin/[. The different results you encounter is caused by different implementations.


In bash, the [ utility accepts CONDITIONAL EXPRESSIONS as the [[ compound command. According to bashs man page both = and == are valid:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

In zsh, the [ utility attempts to implement POSIX and its extensions where these are specified. In the specification of the POSIX test utility there is no == operator defined.

share|improve this answer

[ is a shell builtin command in bash and in zsh:

$ type [
[ is a shell builtin

From the Shell Builtin Commands documentation:

Builtin commands are contained within the shell itself. When the name of a builtin command is used as the first word of a simple command (see Simple Commands), the shell executes the command directly, without invoking another program. Builtin commands are necessary to implement functionality impossible or inconvenient to obtain with separate utilities.

The official documentation ($ help test) only allows to use =:

STRING1 = STRING2

True if the strings are equal.

So, the correct expression would be:

$ [ "a" = "a" ] && echo yes
yes

What happens is that bash is a bit less strict. Supporting the == operator with [ seems to be a bash extension and it is no recommended to use it:

string1 == string2

string1 = string2

True if the strings are equal. When used with the [[ command, this performs pattern matching as described above (see Conditional Constructs).

‘=’ should be used with the test command for POSIX conformance.

If you want to use ==, you should use the [[ keyword:

$ [[ "a" == "a" ]] && echo yes
yes

Keep in mind that [[ is less portable (is not POSIX). But both bash and zsh support it.

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.