loading...
Cover image for Bash Shell Tricks

Bash Shell Tricks

bhaskar_vk profile image Bhaskar Karambelkar ・2 min read

This was originally published on my blog back in 2007, I am glad to see that this has aged well. I still find personally using many of the tricks mentioned here even today.

Quick Command editing

  • ^orig^repl^ replace 'orig' in previous command with 'repl' and execute the new command.

File Name Generation

  • cp filename{,.bak} Copy 'filename' as 'filename.bak.
  • mkdir -p dir{1,2,3}/subdir{1,2} Create dir1/subdir1, dir1/subdir2, dir2/subdir1, dir2/subdir2, dir3/subdir1, and dir3/subdir2 directories

Completion

No I am not talking about completing command/file names. I am talking about completing arguments to various commands, completing filenames based on application. This is one of the touted features of
'zsh', but unknown to many is the fact that it is also available in bash.
All you need to do is install bash-completion.

With bash completion installed you can use the TAB key to complete arguments to common commands like rpm, apt, find, grep etc. Also bash-completion will complete host-names
for ssh, scp, by looking up hosts inside your $HOME/.ssh/authorized_keys file. For rpm based distros, bash-completion will even lookup package names already installed.

The feature I find most handy is file-name completion based on the context of the command. e.g. if you type tar -zxvf and then press the TAB key twice, you will get a list of only files ending in .tar.gz or .tgz rather than a list of all files in the directory.

Socket Communication

I bet a lot of you haven't heard of this, but bash can indeed perform basic socket communication via /dev/tcp, /dev/udp. These are pseudo devices that bash uses to communicate with network sockets. In fact if you did ls -l /dev/tcp /dev/udp you will get a 'No such file or directory' error message.

So how to use them, we below I present 2 examples.

One to quickly check headers from a HTTP Server. Here is a simple function you can put in your $HOME/.bashrc that will check for headers of HTTP server.

headers() {
  server=$1; port=${2:-80}
  exec 5<> /dev/tcp/$server/$port
  echo -e "HEAD / HTTP/1.0\nHost: ${server}\n\n" >&5;
  cat 0<&5;
  exec 5>&-
}

Simply invoke it by

headers <servername or ip> <port>

The port number defaults to 80 if not provided.

Second example is a quick way to check if a port is open or not. You can always use netcat or telnet, but I find this easier.

testPort() {
  server=$1; port=$2; proto=${3:-tcp}
  exec 5<>/dev/$proto/$server/$port
  (( $? == 0 )) && exec 5<&-
}

Again invoke it by

testPort <servername or ip> <port> <protocol>

The protocol can be either tcp or udp and defaults to tcp.

Arithmetic Evaluations

Bash can perform arithmetic evaluations. They are much easier to using expr tool. Below are some examples.Note the absense of $ prefix for variable names.

((count++)) #increment value of variable 'count' by one.
((total+=current)) # set total = total+current.
((current>max?max=current:max=max)) # ternary expression.

Discussion

pic
Editor guide
Collapse
val_baca profile image
Valentin Baca

Neat tips! thanks

Here's mine:

We all know !! but it's mostly just used to sudo !!
I find !$ (which is last argument of the last command) incredibly useful:

#make a directory and go to it
mkdir workspace
cd workspace

# OR even better
mkdir workspace
cd !$

# move then edit a file
mv ~/somefile.txt ~/renamed.txt
vim !$

# edited a file, now add it to git
vim awesome_code.c
git add !$

There's a whole slew of ! commands but !$ is one I use all the time.

Collapse
slariviere profile image
Sébastien Larivière

You can also use esc + . instead of !$. I find more natural and useful if you need to fix a typo.

Collapse
val_baca profile image
Valentin Baca

Even better! Thanks

P.S. For posterity, all of these work just as well in zsh.

Collapse
bhaskar_vk profile image
Bhaskar Karambelkar Author

Funny $_ is the exact same as !$. There's always more to learn 😀.

Collapse
geoff profile image
Geoff Davis

Great write-up!

Quick note, if you are using the command edit/replace feature and are using a conditional command construct (echo "first command" && echo "second command!") the ^foo^bar syntax only replaces the first instance of the searched text.

To replace every instance of that searched text, you have to use !!:gs/foo/bar; going back to my first example:

To replace all the instances of command in...

echo "first command" && echo "second command!"

...you have to execute...

!!:gs/command/echo

...to output:

first echo
second echo!

Further reading: Stack exchange

Collapse
bhaskar_vk profile image
Bhaskar Karambelkar Author

Yup I found out about it sometime after I wrote the original post almost 10 years ago. Thanks for the reminder!

Collapse
kav2k profile image
Alexander Kashev

Small correction: bash completion for SSH looks for $HOME/.ssh/config, not authorized_keys

Collapse
bhaskar_vk profile image
Bhaskar Karambelkar Author

Yikes my bad. Actually it should be $HOME/.ssh/known_hosts file for auto completing host names. You won't find host names in $HOME/.ssh/config unless you've explicitly put them there, but every host you connect to gets saved in known_hosts by default.

Collapse
kav2k profile image
Alexander Kashev

Yes, it does, but bash-completion does not read hosts from known_hosts - at least on my Ubuntu 16.04 machine.

It will, however, read both hostnames and host aliases from config.

Collapse
jorinvo profile image
jorin

Nice writeup! I definitely have look more into /dev/*!

I learn something new that unix tools can do basically every day 😄 In case someone is interested, I try to share those findings on a separate Twitter account: twitter.com/qvlio

Collapse
bobbyiliev profile image
Bobby Iliev

This is a great article!

If you are a fan of opensource, feel free to contribute to the Introduction to Bash Scripting open-source eBook on GitHub!

Collapse
eduardort profile image
Eduardo Reyes

So cool! I also use $_ for the arguments of the last command, echo "something" $_ will be "something"

Collapse
pratikaambani profile image
Pratik Ambani

+1 for the first one. 👌👌

Collapse
oyagci profile image
Oguzhan Yagci

I love shells. They are so powerful. If I can't use one on any of my devices I feel naked