Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: simple question on conditional expression



2025-10-06 12:55:13 +0200, Andreas Kähäri:
[...]
> > if ( echo $ANS | grep B ); then echo OK;fi
[...]
> The "if" statement uses the exit status of the command in parentheses to
> determine whether to execute the "then" block.
[...]

That's rather misleading. While there are shells such as (t)csh
or rc and derivatives where (...) is part of the "if" statement
syntax, that's not the case of zsh and other Bourne-like shells.

The Bourne syntax is:

if
  cmdlistA
then
  cmdlistB
else
  cmdlistC
fi

Which runs cmdlistB if cmdlistA succeeds and cmdlistC otherwise.

(...) in Bourne-like shell is a compound command which is used
to run what's inside in a subshell environment. It's not related
in anyway to the "if" statement.

You do: (umask 077; cd /dir && cmd) for instance for the change
of umask and working directory to be done *only* in the subshell
prior to running cmd.

A (...) compound command exits with the exit status of the last
command run within, so ( echo $ANS | grep B ) will exit with the
exit status of grep, but the (...) to request a subshell
environment are unnecessary here.

A simple command often used in the cmdlistA part of an "if"
statement is the "[" command which can be used to perform a
number of simple tests. "grep" is also often used with the "-q"
(to not output the matching lines) and sometimes "-s" (to not
output any error) to look for matching lines in a file as in:

if
  grep -qe "$regex" < $file
then
  print -r "At least one line matching $regex was found in $file"
else
  print No match
fi

Other *compound* commands commonly used as the condition part of
"if" statements are the ((...)) and [[...]] contructs from the
Korn shell, the former for C-like arithmetic expressions, the
latter for doing mostly the same as what the "[" command does
but using a specific microlanguage.

Here, to test whether a string contains another, you'd use the
latter:

if
  [[ $ANS = *B* ]]
then
  print -r -- "$ANS contains B"
fi

Or the POSIX equivalent:

case $ANS in
  (*B*) printf '%s\n' "$ANS contains B"
esac

If you had to use grep, that would have to be:

if
  echo -E - $ANS | grep -q B
then
  print -r -- "$ANS contains B"
fi

(zsh-specific) or:

if
  print -r -- "$ANS" | grep -q B
then
  print -r -- "$ANS contains B"
fi

(Korn-shell compatible) or:

if
  printf '%s\n' "$ANS" | grep -q B
then
  printf '%s\n' "$ANS contains B"
fi

(POSIX). But I can't think of any reason why you would.

As an extra note, zsh has short forms of the if statement that
can be used if the last command in cmdlistA is a *compound
command* such as (( ... )), [[ ... ]] or (...)

if [[ $ANS = *B* ]] echo match

or:

if [[ $ANS = *B* ]] {print match} else {print no match}

So in the end you can have something looking similar to C:

if (( 3.1416 < 6.02e23 )) {
  echo Avogadro beats Pi
}

Even more C-like than the C-shell where it would be:

if (1 < 2) then
  echo ...
endif

-- 
Stephane




Messages sorted by: Reverse Date, Date, Thread, Author