Compact solution
If you prefer a compact solution, you can use this one:
[ "${URL//[A-Za-z0-9\&.\/=_:?-]}" ] && echo No || echo Yes
Explanation
This solution uses a parameter expansion of the form ${<variable>//<pattern>}
which is a special case of the more general form
${<variable>//<pattern>/<replace>}
This is expanded by the shell to the value of <variable>
, where all matches of <pattern>
are replaced by <replace>
. In our case, <replace>
is empty, what also allows to omit the slash after <pattern>
.
As a result, "${URL//[A-Za-z0-9\&.\/=_:?-]}"
is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ]
is actually [ ]
, which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ]
has the form [ <nes> ]
, where <nes>
is a non-empty string, which yields true (exit status 1).
The overall command is a list of three commands separated by the control operators &&
(and) and ||
(or), which are left-associative. Therefore, the sub-list
[ "${URL//[A-Za-z0-9\&.\/=_:?-]}" ] && echo No
is evaluated first. There, the second operand of &&
is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo
gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo
command: 0 (true).
If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]
: 1 (false).
Now for the rest of the list:
<sub-list> || echo Yes
The ||
operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list>
is false, i.e. for an allowed URL, as it should be.
If structure
Of course you can use the above [ ... ]
command also in an if
structure. In most cases this will yield a better readable code:
if [ "${URL//[A-Za-z0-9\&.\/=_:?-]}" ]; then
echo "That URL is NOT allowed."
else
echo "That URL is allowed."
fi