Some good bash basics and some nice bash tips to make everyday life easier

Really good place where to get detailed explanation what shell commands do is https://explainshell.com/ It’s basically colorize manpage and it has dark theme with random colors!

Since last post was too long I’ll try to keep this one as small as possible and picked only most used stuff

Back to basics

Let’s go over some basics before digging deeper into cool tricks

Chaining flags

Let’s take ls as an example, everyone has used it, to see content of some directory

explainshell

There can’t be anything more basic than that.. ls

mcsneaky@bunter ~/guide
└─$ ls
tempfile

Now, adding some flags, like wanting to see all the hidden files with extra data, like permissions dates etc in there and let’s make it human readable with

ls -l -a -h

mcsneaky@bunter ~/guide
└─$ ls -l -a
total 8
drwxr-xr-x  2 mcsneaky mcsneaky 4096 Aug 24 16:21 .
drwxr-xr-x 12 mcsneaky mcsneaky 4096 Aug 24 15:17 ..
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 16:21 .hidden
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 15:14 tempfile

Now all those flags.. -l -a -h are such a pain to add.. It’s easier to chain them with just like this:

ls -lah

Works exactly the same, just easier to write

mcsneaky@bunter ~/guide
└─$ ls -lah
total 8.0K
drwxr-xr-x  2 mcsneaky mcsneaky 4.0K Aug 24 16:21 .
drwxr-xr-x 12 mcsneaky mcsneaky 4.0K Aug 24 15:17 ..
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 16:21 .hidden
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 15:14 tempfile

Piping |

One command I use quite a lot is checking out what’s listening on some certain TCP port

netstat -tulpn

But since it can give quite a long list of things running it’s a pain to find what’s listening on certain port. Like 1313 for example

then pipe + grep comes handy

netstat -tulpn | grep 1313

explainshell

mcsneaky@bunter ~/guide
└─$ netstat -tulpn | grep 1313
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp    0    0 127.0.0.1:1313    0.0.0.0:*    LISTEN    997/hugo

Nice! Now I know that it’s Hugo that’s listening for port 1313 and since I also know it’s PID I can kill it kill 997 and BOOM! It’s dead

We’ll come back to this: (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)

IO and redirecting

  • Standard input is /dev/stdin or /dev/fd/0 with file descriptor as 0, which defaults to keyboard
  • Standard output is /dev/stdout or /dev/fd/1 with FD of as 1, which defaults to screen
  • Standard error is /dev/stderr or /dev/fd/2 with FD of as.. You guess it 2, which defaults to screen too

process

Those are important to know when you want to mess with some stuff. Really good is to use FDs to get rid of error messages in outputs or to log errors into some file

Above we used netstat -tulpn | grep 1313 which threw some error about root.. I don’t care about this error, so I can just “hide it” (send it to /dev/null)

netstat -tulpn 2> /dev/null | grep 1313

explainshell

mcsneaky@bunter ~/guide
└─$ netstat -tulpn 2> /dev/null | grep 1313
tcp    0    0 127.0.0.1:1313    0.0.0.0:*    LISTEN    997/hugo

BOOM No error!

It’s quite stupid example, but you can do something similar with du -sh /etc/ which is prone to throw a lot of errors like du: cannot read directory '/etc/ssl/private': Permission denied

Can hide all those errors with redirecting standard error to /dev/null

How it works is quite simple. Every process accepts some inputs, does the processing and it writes results to output or error. You can define where those outputs go to tho.

You can also send them both to same file. Let’s have CRON job as an example

*/10 * * * * somecommand >> /cronlog.log 2>&1

It will run somecommand once every 10 minutes, will send standard error to standard output (2>&1) and then will write both to /cronlog.log.

Useful tricks

Some useful / handy tricks to make life lil bit easier

BANG BANG!!

Ever had a problem, that running rm -rf / won’t execute, since need to run it with root permissions?

Easy problem is just to sudo bang!! it

Oke actually don’t bang that, but moving some file won’t be too bad. For example let’s move our tempfile to /srv/ (for whatever reason)

mv ./tmpfile /srv

explainshell

mcsneaky@bunter ~/guide
└─$ mv tempfile /srv/
mv: cannot move 'tempfile' to '/srv/tempfile': Permission denied

And here comes the magic! sudo !!

mcsneaky@bunter ~/guide
└─$ sudo !!
sudo mv tempfile /srv/

!! refers to last executed command. Adding sudo in front of it will execute last command again with elevated permissions

Bash native command “bookmarking”

Execute command and bookmark it:

mcsneaky@bunter ~/guide
└─$ cat /srv/tempfile #tempcontent
tempfile content

Execute command from history by bookmark

mcsneaky@bunter ~/guide
└─$ !?tempcontent
cat /srv/tempfile #tempcontent
tempfile content

!? searches from git history by the end of command

Run the last certain command

# Run ls
mcsneaky@bunter ~/guide
└─$ ls -lah
total 8.0K
drwxr-xr-x  2 mcsneaky mcsneaky 4.0K Aug 24 21:38 .
drwxr-xr-x 12 mcsneaky mcsneaky 4.0K Aug 24 21:53 ..
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 16:21 .hidden
# Run some random command
mcsneaky@bunter ~/guide
└─$ !?tempcontent
cat /srv/tempfile #tempcontent
tempfile content

# Run last `ls` command
mcsneaky@bunter ~/guide
└─$ !ls
ls -lah
total 8.0K
drwxr-xr-x  2 mcsneaky mcsneaky 4.0K Aug 24 21:38 .
drwxr-xr-x 12 mcsneaky mcsneaky 4.0K Aug 24 21:53 ..
-rw-r--r--  1 mcsneaky mcsneaky    0 Aug 24 16:21 .hidden

Replace command but keep the arguments

In case you checked whats in /srv/ folder with ls and now want to cd to there

# Check what's in srv
mcsneaky@bunter ~/guide
└─$ ls /srv/
tempfile
# Move to checked location
mcsneaky@bunter ~/guide
└─$ cd !$
cd /srv/

mcsneaky@bunter /srv
└─$ |

Extra content

Show current git branch near current location

Git branch

Add this to your ~/.bashrc

export PS1='\[\033[0;32m\]\[\033[0m\033[0;32m\]\u\[\033[0;36m\]@\[\033[0;36m\]\h \w\[\033[0;32m\]$(__git_ps1)\n\[\033[0;32m\]└─\[\033[0m\033[0;32m\]\$\[\033[0m\033[0;32m\]\[\033[0m\] '

Feel free to modify it however you like it more

Saving to read-only file in vim (save with sudo)

We all have ended up in situations where we open the file and edit it, but when trying to save then it gives “permission denied”…

Seems like forgot to open that Nginx config file with sudo vim.. Can always close the editor and reopen it, but there’s a lot easier trick:

:w !sudo tee %

It consists onf multiple smaller things

  • :w doesn’t actually write to file, :w writes to buffer and by default it tries to write to same file

  • tee is a T shaped pipe, one pipe output is to file and other pipe output we can just ignore. Could also send it to /dev/null if it makes more sense (but it’s longer to write..) :w !sudo tee > /dev/null %

  • % stands for current file name

  • !sudo pipes the content of current buffer to another command with elevated permissions

sudo save Slightly laggy gif.. Had to fight cat stepping on keyboard :)


Will keep updating this post from time to time