Reputation: 1962
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
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
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
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
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
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
Reputation: 785058
You can combine them all (including if then fi):
[[ -e ./blah && ! -L ./blah ]] && exit 1
Upvotes: 1
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