comatose
comatose

Reputation: 1962

use multiple conditions in 'test' command

I have been trying to convert the following code to use 'test' instead of 'if'

if [ -e ./blah ] &&  [ ! -L ./blah ];
then
   exit 1
fi

My intention is to use test instead, so that I dont have to exit 1 explicitly. I am trying something like this:

test -e ./blah  && ! -L ./blah;

instead of &&, I have tried -a, with different bracket combinations, but I am not successful. I am sure there should be a simple way to do this. Can anyone help me ?

Upvotes: 3

Views: 3511

Answers (7)

David W.
David W.

Reputation: 107040

Do the following:

$ ls -i /bin/test
54008404 /bin/test
$ ls -i /bin/[
54008404 /bin/test

That 54008404 is the inode number. This is the real name of a file. The /bin/test simply points to the inode and the inode contains all file file information.

The thing to note is that /bin/[ and /bin/test are the same inode. That means, they're the same command.

Thus:

if [ -f "$foo" ]

is the same as:

if test -f "$foo"

The if command executes the command given, and then will execute the if clause if the command returns true and doesn't execute the clause if the command it false.

For example:

if grep -q "foo" $foo
then
    echo "File $foo contains the regular expression /foo/"
fi

Is completely valid. The grep -q command (in many variants of grep means search for the regular expression, and if that regular expression is in the file, return an exit code of 0 (which means the command succeeded and is true).

Note there is no square brackets.

The test command (or [...]) merely runs a test as specified, and returns with an exit code of 0 (thus the command is a success) if the test is true. That's all it does.

You may also see this construct:

[ "$foo" = "$bar" ] && echo "$foo is equal to $bar"

The && means execute the next command (and return the exit code) if the first command returns an exit code of zero. Otherwise, simply return the first command's exit code.

Thus:

if [ -e ./blah ] &&  [ ! -L ./blah ];

is saying run test -e ./blah and if that is true (that is, the file exists) execute test ! -L ./blah and if that is also true, run the if clause of the statement.

Note that [ -e ./blah] and [ ! -L ./blah ] are two separate commands. The && strings together the two commands:

[ "$foo" = "$bar" ] && some_command;

This says, run test "$foo" = "$bar" and if that is true, run the command some_command. Note that this is equivalent to:

if [ "$foo" = "$bar" ]
then
    some_command
fi

The other list structure is the ||. This means that if the first command succeeds, return an exit code of 0 and don't run the second command. Thus:

[ "$foo" = "$bar" ] || some_command;

Is the same as:

if [ "$foo" = "$bar" ]
then
    :
else
     some_command
fi

Let's get back to your _original question:

if [ -e ./blah ] &&  [ ! -L ./blah ];
then
   exit 1
fi

Is the same as:

if test -e ./blah && test ! -L ./blah
then
    exit 1
fi

Which is the same as

test -e ./blah && test ! -L ./blah && exit 1

This means: If test -e ./blah is true (./blah is a file), then execute the command after the && list operator. This is test -! -L ./blah. If this test also is true, run the command after the && list operator again.

This could also be rewritten as:

test -e ./blah && test -L ./blah || exit 1

This says that if test -e ./blah is true, run the command after the && list operator. If test -L ./blah is false, run the command after the || operator.

Upvotes: 1

l0b0
l0b0

Reputation: 58788

if [ -e ./blah ] && [ ! -L ./blah ];

is equivalent to

if test -e ./blah && test ! -L ./blah;

Therefore you can simply write

test -e ./blah && test ! -L ./blah

To wit:

$ help [\[] | tail -n +3
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Upvotes: 3

Bill
Bill

Reputation: 5764

To make if [ -e ./blah ] && [ ! -L ./blah ]; work, use the following if [ -e ./blah -a ! -L ./blah ]; (-a stands for and) http://tldp.org/LDP/abs/html/comparison-ops.html

Demo -- http://ideone.com/GR8UiK

But, as others have pointed out, [[ .. ]] construct is more powerful than [...].

Upvotes: 2

aymericbeaumet
aymericbeaumet

Reputation: 7332

As you ask to use test, you can do like so:

test -e ./blah && test -L ./blah || ( echo 'First action' ; echo 'Second action )

The different operators (&&, ||, etc...) are first parsed by the shell, so you can't use it in command parameter(s).

Upvotes: 1

jaypal singh
jaypal singh

Reputation: 77095

Use [[ keyword as it is more powerful.

if [[ -e ./blah && ! -L ./blah ]]
    then
    ...
fi

However, to ensure portability, you can do something like this too

if [ -e ./blah ] && [ ! -L ./blah  ] 
    then
    ...do something
fi

Upvotes: 1

anubhava
anubhava

Reputation: 785058

You can combine them all (including if then fi):

[[ -e ./blah && ! -L ./blah ]] && exit 1

Upvotes: 1

choroba
choroba

Reputation: 241828

test does not understand logical operators && and ||. You can use test -e ./blah -a ! -L ./blah, but if you are using bash, you can also switch to its more powerful [[ .. ]] construct:

[[ -e ./blah && ! -L ./blah ]] 

Upvotes: 7

Related Questions