Why does if [ !$(grep -q) ] not work when if grep -q does?
A number of things are wrong with that first snippet.
You don't want [ ... ]
if you want to test the return code. Drop those.
[]
is not part of the if
syntax (as you can see from your second snippet).
[
is a shell built-in and binary on your system. It just exits with a return code. if ...; then
tests the return code of ...
.
$()
is command substitution. It replaces itself with the output from the command that was run.
So [ !$(grep ...) ]
is actually evaluating [ !output_from_grep ]
and [ word ]
is interpreted as [ -n word ]
which will be true whenever word
is non-empty. Given that !
is never non-empty that will always be true.
Simply, as indicated by @thom in his comment (a bit obliquely), add the !
negation to your second snippet with a space between it and grep
.
What is the point of grep -q
The exit status of grep
doesn't necessarily indicate an error ; it indicates success or failure. grep
defines success as matching 1 or more lines. Failure includes matching zero lines, or some other error that prevented matching from taking place in the first place.
-q
is used when you don't care about which lines matched, only that some lines matched.
if grep -q foo file.txt; then
echo "file.txt contains foo"
else
echo "file.txt does not contain foo"
fi
Why did I get different answers when I changed grep to egrep in the latter half of each
In egrep
(or, preferably, grep -E
), the |
is a metacharacter, whereas in plain grep
it is a plain (non-meta) character.
The |F$
term in egrep
looks for an empty string or F
at the end of line; it finds an empty string on every line.
The same term in grep
looks for a |F
at the end of line. To look for that with egrep
, you'd need to escape the metacharacter with a backslash: grep -E '\|F$' enrolments
.
In short, the plain grep
command understands Basic Regular Expressions (BRE). The egrep
or 'extended grep
' command understands Extended Regular Expressions (ERE). Some versions of grep
(such as GNU grep
) can be compiled to recognize Perl-Compatible Regular Expressions (PCRE).
Why doesn't if [ echo $foo | grep -q bar ] work?
Short Answer
For your immediate use case, you simply want:
if echo "$confirm" | grep -q y; then
...or its much more efficient equivalent (if your shell is bash):
if [[ $confirm = *y* ]]; then
...or its much more efficient equivalent (for any POSIX shell):
case $confirm in *y*) echo "Put your code for the yes branch here" ;; esac
Why was the original wrong?
[
is not part of if
syntax: if
simply takes a (potentially compound) command as its argument before the then
. [
is different name for the test
command, which runs checks on its arguments; however, if what you want to test is the exit status of grep -q
, then the test
command doesn't need to be invoked for this purpose at all.
If you put a |
inside a [
command, that makes your compound command a pipeline, and starts a new simple command. Arguments after the |
are thus no longer passed to [
.
With your original code:
if [ echo $confirm | grep -q y ]; then
...this was running two commands, with a pipeline between them:
[ echo $confirm # first command
grep -q y ] # second command
Since [
requires that its last argument be ]
, it reported that that mandatory argument was missing; and since grep
treats extra arguments as filenames to read, it complained that no file named ]
could be found.
Also, [ "$foo" ]
checks whether the contents of foo
is nonempty. Since the output of grep -q
is always empty, [ "$(echo "$confirm" | grep -q y)" ]
, while syntactically correct, would always evaluate to false, even while exit status of grep -q
changes to indicate whether a match was found. ([ "$(echo "$confirm" | grep y)" ]
, by contrast, is an alternative that emits a correct result - using [ ]
to test whether the output from grep
is or is not empty -- but is much less efficient than the best-practice approaches).
Formal if
syntax
From help if
:
if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
The
if COMMANDS
list is executed. If its exit status is zero, then the
then COMMANDS
list is executed. Otherwise, eachelif COMMANDS
list is
executed in turn, and if its exit status is zero, the corresponding
then COMMANDS
list is executed and the if command completes. Otherwise,
theelse COMMANDS
list is executed, if present. The exit status of the
entire construct is the exit status of the last command executed, or zero
if no condition tested true.
Notably, if
takes a list of COMMANDS, and no [
is included in the syntax specification.
Grep ascending order of cards. Why does it work?
Your regex is not at all valid, so I don't understand why you say it works.
Plain grep
does not understand |
to mean alteration. You can add an -E
option to specify ERE (traditionally, egrep
) regex semantics, or with POSIX grep
backslash the |
; or you can specify multiple -e
options. (See e.g. https://en.wikipedia.org/wiki/Regular_expression#Standards for some background about the various regex dialects in common use.)
grep -Ev "[KQJT].*[2-9A].* |[KQ].*[JT].* |[6-9].*[2-5A].* "
grep -v "[KQJT].*[2-9A].* \|[KQ].*[JT].* \|[6-9].*[2-5A].* "
grep -ve "[KQJT].*[2-9A].* " -e "[KQ].*[JT].* " -e "[6-9].*[2-5A].* "
Even with this fix, the regex is obviously insufficient for removing matches where e.g. 3 is followed by 2. The only way to make it cover all cases is to enumerate every possibility. (Disallow 1 followed by any higher number, 2 followed by any higher number, 3 followed by any higher number, etc.) An altogether better approach would be to use a scripting language of some sort, and basically just map the symbols to ones with the desired sort order, then check if the input is sorted.
If that is not an option, maybe try
grep -E '^(A.)*(2.)*(3.)*(4.)*(5.)*(6.)*(7.)*(8.)*(9.)*(T.)*(J.)*(Q.)*(K.)* '
which looks for zero or more aces, followed by zero or more twos, followed by zero or more threes, etc.
How to use grep in if statement in shell
There is very likely no command named [grep
. Drop the [
if grep -q "<pr>$i</pr>" ./archiv; then ...
[
is not and has never been a part of the shell grammar. It is a command, just like echo
or test
or grep
. The value returned by that command is used to determine whether or not to execute the clause of the if
statement.
/usr/xpg4/bin/grep -q [^0-9] does not always work as expected
Your validity test function happens to be more complicated than it should be. E.g. why do you use a command substitution with print
for ${#1}
? Why don't you use ${#1}
directly? Next, forking grep to test for a non-number is a slow and expensive operation. What about this equivalent function, 100% POSIX and blazingly fast:
is_valid_id () {
# Takes one argument, which is the ID being tested.
if test ${#1} -ne 10; then
return 1 # ID length not exactly 10.
fi
case $1 in
(*[!0-9]*) return 1;; # ID contains a non-digit.
(*) return 0;; # ID is exactly 10 digits.
esac
}
Or even more simple, if you don't mind repeating yourself:
is_valid_id () {
# Takes one argument, which is the ID being tested.
case $1 in
([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]) # 10 digits.
return 0;;
(*)
return 1;;
esac
}
This also avoids your unquoted use of a grep
pattern, which is error-prone in the presence of one-character file names. Does this work better?
Why wont my bashrc script work?
You don't want cmd-substitution for your tests, try
if screen -ls | grep -q ".testSession (Detached)" ; then
screen -r testSession
elif screen -ls | grep -q "No Sockets found"; then
screen -S testSession
else
echo "There is already a session with the Primary ID attached"
fi
Recall that if
evaluates any following cmd-group for its return value (up to the closing ; then
). The [
is an alias for the test
command, but as grep -q
will return 0
if your string is found and something >0
for other cases, this is all you need to test your screen connections.
IHTH
Related Topics
Limit Useable Host Resources in Docker Compose Without Swarm
Get a Spectrum of Frequencies from Wav/Riff Using Linux Command Line
How to Print a Number in Arm Assembly
Switching Users Using Winscp Between Different Accounts
How Can a Process Try to Access Other Process's Memory in Linux Virtual Memory System
Difference Between Kernel, Kernel-Thread and User-Thread
Accessing Files Outside the Document Root with Apache
Nasm Print One Character at a Time
Qmake .Pro File Not Parsed Correctly to Generate Ld_Library_Path
Passing Environment Variables Not Working with Docker
Low-Overhead Way to Access the Memory Space of a Traced Process
Catching a Direct Redirect to /Dev/Tty
Shell Command to Update Pom File from a Variable
"Cannot Write to Log File Pg_Upgrade_Internal.Log" When Upgrading from Postgresql 9.1 to 9.3