What Exactly Is Sudo Bang Bang

What exactly is sudo bang bang?

The bang bang (!!) command is a shortcut to repeat the previous command you entered in your terminal. This command is very useful when you forget that you need admin rights to make a certain action, and lets you repeat it with super-user rights just by typing

sudo !!

instead of typing arrow-up, scrolling to the beginning of the line, adding sudo and hitting enter (imagine scrolling through those loooong apt-get commands). So many seconds gained! Yay!

sudo bang bang

There are many other bang-commands such as !x, !?x, !!:p and !!*. This blog post lists them and explains what they are for.

What is bang dollar (!$) in Bash?

That's the last argument of the previous command. From the documentation:


designates the last argument of the preceding command. This may be shortened to !$.

Remark. If you want to play around with Bash's history, I suggest you turn on the shell option histverify like so:

shopt -s histverify

(you can also put it in your .bashrc to have it on permanently). When using history substitution, the substitution is not executed immediately; instead, it is put in readline's buffer, waiting for you to press enter… or not!

To make things precise, typing !$ is not equivalent to typing "$_": !$ is really a history substitution, refering to the last word of the previous command that was entered, whereas "$_" is the last argument of the previously executed command. You can compare both (I have shopt -s histverify):

$ { echo zee; }
$ echo "$_"
$ { echo zee; }
$ echo !$
$ echo }


$ if true; then echo one; else echo two; fi
$ echo "$_"
$ if true; then echo one; else echo two; fi
$ echo !$
$ echo fi

And also:

$ echo zee; echo "$_"
$ echo zee2; echo !$
$ echo zee2; echo "$_"

And also

$ echo {1..3}
1 2 3
$ echo "$_"
$ echo {1..3}
1 2 3
$ echo !$
$ echo {1..3}

And also

$ echo one ;
$ echo "$_"
$ echo one ;
$ echo !$
$ echo ;

There are lots of other examples, e.g., with aliases.

How does the vim write with sudo trick work?

In :w !sudo tee %...

% means "the current file"

As eugene y pointed out, % does indeed mean "the current file name", which is passed to tee so that it knows which file to overwrite.

(In substitution commands, it's slightly different; as :help :% shows, it's equal to 1,$ (the entire file) (thanks to @Orafu for pointing out that this does not evaluate to the filename). For example, :%s/foo/bar means "in the current file, replace occurrences of foo with bar." If you highlight some text before typing :s, you'll see that the highlighted lines take the place of % as your substitution range.)

:w isn't updating your file

One confusing part of this trick is that you might think :w is modifying your file, but it isn't. If you opened and modified file1.txt, then ran :w file2.txt, it would be a "save as"; file1.txt wouldn't be modified, but the current buffer contents would be sent to file2.txt.

Instead of file2.txt, you can substitute a shell command to receive the buffer contents. For instance, :w !cat will just display the contents.

If Vim wasn't run with sudo access, its :w can't modify a protected file, but if it passes the buffer contents to the shell, a command in the shell can be run with sudo. In this case, we use tee.

Understanding tee

As for tee, picture the tee command as a T-shaped pipe in a normal bash piping situation: it directs output to specified file(s) and also sends it to standard output, which can be captured by the next piped command.

For example, in ps -ax | tee processes.txt | grep 'foo', the list of processes will be written to a text file and passed along to grep.

     +-----------+    tee     +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
| |
| processes.txt |
| |

(Diagram created with Asciiflow.)

See the tee man page for more info.

Tee as a hack

In the situation your question describes, using tee is a hack because we're ignoring half of what it does. sudo tee writes to our file and also sends the buffer contents to standard output, but we ignore standard output. We don't need to pass anything to another piped command in this case; we're just using tee as an alternate way of writing a file and so that we can call it with sudo.

Making this trick easy

You can add this to your .vimrc to make this trick easy-to-use: just type :w!!.

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

The > /dev/null part explicitly throws away the standard output, since, as I said, we don't need to pass anything to another piped command.

cygwin clearscreen from bash

If it's contained in your cygwin install (run Cygwin's setup and make sure you have the package called "ncurses"), try

tput clear

Is it possible to trace my shell(bash, fish, zsh)?

I figured it out though without tracing the fish shell syscalls or something like that I realized that I am using oh-my-fish plugin or framework and it is loading a theme which displayed the unwanted message, thanks for the tips though I at least now know how to trace the fish shell

How do I enable !! in fish?

The fish shell deliberately omits history substitution.

#!/usr/bin/python (sha-bang or she-bang)does not work in bash

The bash documentation is correct: when you enter ./demo.py at the bash command prompt, bash uses the shebang line to figure out what executable will run the script.

When you do bash demo.py then of course bash is going to try to run it as a bash script. Because you told it to. (Imagine if you had a bash script with an incorrect shebang line -- how would you run it? By passing it directly to bash, in just this way.)

If you want to start another bash shell which runs your Python script, then use bash -c ./demo.py to execute demo.py as a bash command rather than as a bash script. But you shouldn't need to start another shell just to run a Python script.

Using redirection in a linux shell script which run as sudo

I guess, that your script test.sh does not have a shebang in the first line like this:


Without this line several environment settings affect the way your script is executed. In your case this means that another shell like ash, ksh, dash or whatever will be used to execute the script due to the setting of the root user.

Should I put #! (shebang) in Python scripts, and what form should it take?

The shebang line in any script determines the script's ability to be executed like a standalone executable without typing python beforehand in the terminal or when double clicking it in a file manager (when configured properly). It isn't necessary but generally put there so when someone sees the file opened in an editor, they immediately know what they're looking at. However, which shebang line you use is important.

Correct usage for (defaults to version 3.latest) Python 3 scripts is:

#!/usr/bin/env python3

Correct usage for (defaults to version 2.latest) Python 2 scripts is:

#!/usr/bin/env python2

The following should not be used (except for the rare case that you are writing code which is compatible with both Python 2.x and 3.x):

#!/usr/bin/env python

The reason for these recommendations, given in PEP 394, is that python can refer either to python2 or python3 on different systems.

Also, do not use:


"python may be installed at /usr/bin/python or /bin/python in those
cases, the above #! will fail."

―"#!/usr/bin/env python" vs "#!/usr/local/bin/python"

Related Topics

Leave a reply