Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><sup><em>Previously, the answer was presented with what's now the first section as the last section.</em></sup></p> <h3>POSIX Shell includes a <code>!</code> operator</h3> <p>Poking around the shell specification for other issues, I recently (September 2015) noticed that the POSIX shell supports a <code>!</code> operator. For example, it is listed as a <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_04" rel="noreferrer">reserved word</a> and can appear at the start of a <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_02" rel="noreferrer">pipeline</a> — where a simple command is a special case of 'pipeline'. It can, therefore, be used in <code>if</code> statements and <code>while</code> or <code>until</code> loops too — in POSIX-compliant shells. Consequently, despite my reservations, it is probably more widely available than I realized back in 2008. A quick check of POSIX 2004 and SUS/POSIX 1997 shows that <code>!</code> was present in both those versions.</p> <p>Note that the <code>!</code> operator must appear at the <em>beginning</em> of the pipeline and negates the status code of the entire pipeline (i.e. the <em>last</em> command). Here are some examples.</p> <pre><code># Simple commands, pipes, and redirects work fine. $ ! some-command succeed; echo $? 1 $ ! some-command fail | some-other-command fail; echo $? 0 $ ! some-command &lt; succeed.txt; echo $? 1 # Environment variables also work, but must come after the !. $ ! RESULT=fail some-command; echo $? 0 # A more complex example. $ if ! some-command &lt; input.txt | grep Success &gt; /dev/null; then echo 'Failure!'; recover-command; mv input.txt input-failed.txt; fi Failure! $ ls *.txt input-failed.txt </code></pre> <h3>Portable answer — works with antique shells</h3> <p>In a Bourne (Korn, POSIX, Bash) script, I use:</p> <pre><code>if ...command and arguments... then : it succeeded else : it failed fi </code></pre> <p>This is as portable as it gets. The 'command and arguments' can be a pipeline or other compound sequence of commands.</p> <h3>A <code>not</code> command</h3> <p>The '!' operator, whether built-in to your shell or provided by the o/s, is not universally available. It isn't dreadfully hard to write, though - the code below dates back to at least 1991 (though I think I wrote a previous version even longer ago). I don't tend to use this in my scripts, though, because it is not reliably available.</p> <pre><code>/* @(#)File: $RCSfile: not.c,v $ @(#)Version: $Revision: 4.2 $ @(#)Last changed: $Date: 2005/06/22 19:44:07 $ @(#)Purpose: Invert success/failure status of command @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1991,1997,2005 */ #include &lt;stdlib.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/types.h&gt; #include &lt;sys/wait.h&gt; #include "stderr.h" #ifndef lint static const char sccs[] = "@(#)$Id: not.c,v 4.2 2005/06/22 19:44:07 jleffler Exp $"; #endif int main(int argc, char **argv) { int pid; int corpse; int status; err_setarg0(argv[0]); if (argc &lt;= 1) { /* Nothing to execute. Nothing executed successfully. */ /* Inverted exit condition is non-zero */ exit(1); } if ((pid = fork()) &lt; 0) err_syserr("failed to fork\n"); if (pid == 0) { /* Child: execute command using PATH etc. */ execvp(argv[1], &amp;argv[1]); err_syserr("failed to execute command %s\n", argv[1]); /* NOTREACHED */ } /* Parent */ while ((corpse = wait(&amp;status)) &gt; 0) { if (corpse == pid) { /* Status contains exit status of child. */ /* If exit status of child is zero, it succeeded, and we should exit with a non-zero status */ /* If exit status of child is non-zero, if failed and we should exit with zero status */ exit(status == 0); /* NOTREACHED */ } } /* Failed to receive notification of child's death -- assume it failed */ return (0); } </code></pre> <p>This returns 'success', the opposite of failure, when it fails to execute the command. We can debate whether the 'do nothing successfully' option was correct; maybe it should report an error when it isn't asked to do anything. The code in '<code>"stderr.h"</code>' provides simple error reporting facilities - I use it everywhere. Source code on request - see my profile page to contact me.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload