Shell Exclamation Mark Command

what does exclamation mark mean in linux?

Note that ! does not have a special meaning in Linux (the operating system), but in several standard programs in Linux. In your case it is not so much a feature of bash (as Mark Bramnik claimed in his otherwise correct answer), but of the standard program called test or [. Since bash emulates this command internally, of course it has to interpret the ! as well, but the definition can be found by doing a man test, where it is described as:

   ! EXPRESSION
EXPRESSION is false

Actually, bash does have a ! too, with a related, but not identical meaning. If you invoke a program by prefix it with !, i.e.

! prog

bash sets the exit code to 0 if prog terminated with a non-zero exit code, and sets it to 1 if prog terminated with exit code zero. Therefore, you could have written

[ ! -d cc201 ]

equally well as

! [ -d cc201 ]

The overall effect is the same, but the former is the ! from test, which in turn in emulated by bash, while the latter is the builtin ststus-code negator of bash.

In bash what does ! (exclamation mark) before command means?

In bash, if you type ! followed by a command name, it will substitute it with the last command in your history starting by that name.

So in your case !git was substituted with git clone somerepo so the whole line was translated to git clone somerepo status

What is exclamation mark at beginning of line doing in this BASH snippet?

The set -e command tells bash to exit if a pipeline returns a non-zero exit status (basically if a command fails).

The ! negates the exit status, but it also inhibits the effect of set -e. The idea is that if a command is being executed as part of a condition, you don't want to terminate the shell. If it's preceded by !, the shell effectively assumes that it's being executed as a condition (even if the result is ignored).

Quoting the bash manual:

The shell does not exit if the command that fails is part of the
command list immediately following a 'while' or 'until' keyword, part
of the test in an 'if' statement, part of any command executed in a
'&&' or '||' list except the command following the final '&&' or '||',
any command in a pipeline but the last, or if the command's return
status is being inverted with '!'.

https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

(You're correct that the ! has nothing to do with history substitution in this context.)

The return code for the read built-in is

zero, unless end-of-file is encountered, read times out (in which case it's
greater than 128), a variable assignment error occurs,
or an invalid file descriptor is supplied as the argument to -u.

The relevant case here is end-of-file. Redirecting the input of read using <<EOT (and disabling normal termination using -d '') means that the read command will encounter an end-of-file, which would cause it to return a non-zero status. The ! prevents this from aborting the script (but the value is still assigned to $SOME_VAR).

What's the meaning of a ! before a command in the shell?

TL;DR: This is just by-passing the set -e flag in the specific line where you are using it.


Adding add to hek2mgl's correct and useful answer.

You have:

set -e
! command

Bash Reference Manual → Pipelines describes:

Each command in a pipeline is executed in its own subshell. The exit status of a pipeline is the exit status of the last command in the pipeline (...). If the reserved word ‘!’ precedes the pipeline, the exit status is the logical negation of the exit status as described above. The shell waits for all commands in the pipeline to terminate before returning a value.

This means that ! preceding a command is negating the exit status of it:

$ echo 23
23
$ echo $?
0
# But
$ ! echo 23
23
$ echo $?
1

Or:

$ echo 23 && echo "true" || echo "fail"
23
true
$ ! echo 23 && echo "true" || echo "fail"
23
fail

The exit status is useful in many ways. In your script, used together with set -e makes the script exit whenever a command returns a non-zero status.

Thus, when you have:

set -e
command1
command2

If command1 returns a non-zero status, the script will finish and won't proceed to command2.

However, there is also an interesting point to mention, described in 4.3.1 The Set Builtin:

-e

Exit immediately if a pipeline (see Pipelines), which may consist of a single simple command (see Simple Commands), a list (see Lists), or a compound command (see Compound Commands) returns a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits.


Taking all of these into consideration, when you have:

set -e
! command1
command2

What you are doing is to by-pass the set -e flag in the command1. Why?

  • if command1 runs properly, it will return a zero status. ! will negate it, but set -e won't trigger an exit by the because it comes from a return status inverted with !, as described above.
  • if command1 fails, it will return a non-zero status. ! will negate it, so the line will end up returning a zero status and the script will continue normally.

How do I escape an exclamation mark in bash?

Exclamation mark is preserved literally when you include it in a single-quoted string.

Example:

git commit -m 'Frustrating <insert object of frustration here>!'

Running bash command using exclamation mark not working with python prompt

This is the shell assignment feature of IPython, not a core part of Python itself. The fact that you don't see the In [1]: style of prompts (you have >>>) means that you're not running IPython.


If you want to run a shell command from "normal" Python, the usual approach is with something like:

import os
os.system("whatever")

Just keep in mind the shell assignment feature is a tad more powerful than that.


If you need that feature, and you have IPython correctly installed, just run ipython instead of python.

exclamation mark to test variable is true or not in bash shell

tl;dr

[ ! $bar ] treats $bar as a string, and any nonempty string is considered "true" - including literal false; in other words: [ ! 'true' ] && [ ! 'false' ] both evaluate to "false", because the operands are nonempty strings in both cases and ! negates the outcome.

Therefore, you must use string comparison:

bar=false
if [ ! "$bar" = 'true' ]; then # same as: [ "$bar" != 'true' ]
echo 'bar is false'
else
echo 'bar is true'
fi

In Bash, you can also use [[ ! $bar == 'true' ]] or [[ $bar != 'true' ]]; unless you need to remain POSIX-compliant, I suggest using [[ ... ]].


In the context of [ ... ] and [[ ... ]] (Bash-specific), variable values are strings by default, and, generally, POSIX-like shells have no explicit Boolean data type.

Unary operator ! interprets its operand implicitly as a Boolean, and a string in a Boolean context is interpreted as follows:

  • only an empty string is considered "false" (exit code 1(!))
  • any nonempty string - including literal false - is considered "true" (exit code 0(!))

Thus, ! $bar evaluates to "false", because $bar - containing nonempty string 'false' - evaluates to "true", and ! inverts that.


! can also be used outside of conditionals to directly negate the success status of commands (including [).

Since false and true also exist as command names (typically, as shell builtins), you could do the following, but do note that it only works as intended with variable values that are either the literals false or true:

bar=false
if ! "$bar"; then
echo 'bar is false'
else
echo 'bar is true'
fi

Background information

POSIX-like shells only have 2 basic (scalar) data types:

  • strings (by default):

    • In [ ... ] and [[ ... ]] conditionals, operators = (== in Bash),<,<=,>,>=` perform string comparison.
  • integers:

    • In [ ... ] and [[ ... ]] conditionals, distinct arithmetic operators (-eq, lt, le, gt, ge) must be used to perform numerical comparison

    • Alternatively, in an arithmetic expansion ($(( ... ))), ==, <, <=, >, >= have their usual, numeric meaning.

      In Bash, you can also use (( ... )) as an arithmetic conditional.

Note: Per POSIX, you cannot type a variable as an integer (because there is no way to declare a shell variable), so it is only implicitly treated as one in comparisons using arithmetic operators / in arithmetic contexts.

In Bash, however, you can declare integer variables with declare -i / local -i, but in conditionals / arithmetic contexts it is still the choice of operator / arithmetic context that determines whether the value is treated as a string or as an integer.


Booleans in shells are expressed implicitly as exit codes, in a reversal of the usual Boolean-to-integer mapping:

  • "true" maps to exit code 0(!)
  • "false" is expressed as exit code 1(!) or any other nonzero exit code.

Shell exclamation mark command

See the Bash manual, "Event Designators":

!string

Refer to the most recent command preceding the current position in the history list starting with string.

This means that !g++ runs the last command that began with g++, calling the GNU C++ compiler:

$ g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran
...
(g++ does its job here)
...
$ vim test
...
(other commands)
...
$ !g++
g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran <-- same command as before

!cat filename, on the other hands, doesn't make a lot of sense as it's already a complete command. Unless there was a super complicated pipe after that command the last time, of course, which the event designator would then repeat.



Related Topics



Leave a reply



Submit