Bash Tips - Tip 1

MAY 2, 2017 • Written by David Grieser

Recently, I was pairing with a developer on a client’s team. He was stuck and couldn’t figure out how to fix the problem. I had a look and guided him through a series of bash and other shell commands until we found the solution. After thanking me – he had been at it for hours – he asked me “How do you know all of this?” I could tell from his tone that what he was really asking was “From what book did you learn all of this?” Thing is, I didn’t learn “all of this” from a book. Having been at it since 1997, I learned it through good old fashioned trial and error. That and being exposed to new tools.

That conversation sparked the idea that I should share this knowledge through a series of posts. My goal is to make it easily accessible for all who could use this information. If you have pressing needs, let me know, and I might cover that tip next.

For now, here’s tip number one:

Aliases

An alias is similar in the real world as it is in a shell. So if we look at the ls command, which lists all of the files in the current directory, we’ll see something like this.

$ ls -a
.             ..            .bash_profile .git          .tmux.conf    .vimrc        README.md     alacritty.yml

What if we want this list to be vertical and show file sizes in human-readable format? The command would be:

$ ls -alh
total 48
drwxr-xr-x    8 david  staff   272B Jan 11 09:41 .
drwxr-xr-x+ 117 david  staff   3.9K Feb 22 11:27 ..
-rw-r--r--    1 david  staff   2.2K Nov 30 17:00 .bash_profile
drwxr-xr-x   14 david  staff   476B Sep 23 13:09 .git
-rw-r--r--    1 david  staff   1.2K Jun 28  2016 .tmux.conf
-rw-r--r--    1 david  staff   2.6K Jan 26 01:04 .vimrc
-rw-r--r--    1 david  staff    79B Oct 12  2014 README.md
-rw-r--r--    1 david  staff   7.3K Jan 11 09:49 alacritty.yml

And if we want to be able to access this quickly, we can set it up as an alias.

$ alias lh='ls -alh'

Now, anytime we type lh into our shell, it will give us the same output.

$ lh
total 48
drwxr-xr-x    8 david  staff   272B Jan 11 09:41 .
drwxr-xr-x+ 117 david  staff   3.9K Feb 22 11:27 ..
-rw-r--r--    1 david  staff   2.2K Nov 30 17:00 .bash_profile
drwxr-xr-x   14 david  staff   476B Sep 23 13:09 .git
-rw-r--r--    1 david  staff   1.2K Jun 28  2016 .tmux.conf
-rw-r--r--    1 david  staff   2.6K Jan 26 01:04 .vimrc
-rw-r--r--    1 david  staff    79B Oct 12  2014 README.md
-rw-r--r--    1 david  staff   7.3K Jan 11 09:49 alacritty.yml

However, if we want this alias to persist, we need to store it somewhere. When using bash, there’s a config file we can reference. For nix systems, it should be ~/.bashrc, and for Mac OS X, ~/.bash_profile. This file is used when the shell starts to set up its environment. This file will most likely already exist, so let’s add our new alias.

# Setup Alias for lh
alias lh='ls -alh'

This is in the config for bash, but our current shell has the old configuration loaded. To load the new config changes, we need to source this file.

$ source ~/.bash_profile

Now, our current shell and any future ones will have our new alias available.

SSHing into Different Machines

If you’ve ever used an Amazon EC2 instance, set up a local Virtual Machine (VM), or accessed another machine across the internet, you might have used ssh, which stands for Secure SHell. A typical connection might look like this:

ssh ssh.someserver.com -l myusername -p 9000 -i "~/.ssh/my_keyfile.pem"

Since I don’t want to have to remember this all the time, what are my options?

alias

I could create an alias for this connection:

# include in ~/.bash_profile or ~/.bashrc
alias ssh-someserver='ssh ssh.someserver.com -l myusername -p 9000 -i "~/.ssh/my_keyfile.pem"'

This works, but the list could grow quite large if we have numerous servers we need to connect to.

And… there is a built-in solution to handle this with ssh.

ssh config

By default, ssh uses the path ~/.ssh/config as a place to look up information if it is available. This means we can add the connection information to this server and access it with ssh.

# include in ~/.ssh/config
Host someserver
  Hostname ssh.someserver.com
  Port 9000
  User myusername
  IdentityFile "~/.ssh/my_keyfile.pem"

Now, all we have to do is use the Host name to ssh into this machine.

ssh someserver

And all we have to remember now is which server we want to connect to and type its name after ssh. The added benefit is this config file works with other ssh tools like scp.

Securely Copy Files

The scp command works similarly to the cp command, but can access other machines via ssh.

scp someserver:~/project/README.md ~/Downloads/project-README.md

Here, we’re going to copy the README.md file from the project folder on the someserver box and put it into our local Downloads folder, but rename it to project-README.md since we want to know which readme this is for.

Stopping a Local Process

There are times when we might leave our ssh session open and, after a period of time or if the internet connection is lost, the ssh session will become unresponsive. If we weren’t running an active task remotely, the ssh session isn’t really “hung,” but rather, it’s trying to re-establish a connection. This can be frustrating if we know the connection won’t go through as that bash session will not be usable.

The quickest way, that I have found, to get control of that window back is the following:

  1. Start a new Terminal/bash window.
  2. Run ps aux | grep ssh.
  3. Find the pid of the “hung” ssh connection.
  4. Run kill <pid>.

The goal here is to find the ssh session that most likely will fail anyway and tell it to exit. This is what it would look like:

$ ps xao user,pid,comm | grep ssh
david           16510  vim .ssh/config
david           21462  /usr/bin/ssh-agent -l
david           16738  grep --color -E ssh
david           16733  ssh my_remote_server
$ kill 16733

Typically, I use ps aux, but for formatting reasons on this post, I thought it would be helpful to only show the username (user) of the active process, the process id (pid) – to determine what to pass to the kill command – and the command (comm) itself.

Running the kill command most likely won’t show anything in the second shell we are using, but in the first shell, that ssh connection will end up looking something like this:

myusername@someserver:~$ Killed by signal 15.
$

A lot of developers just use the kill -9 command. This specifies the signal to send to the program. The list of kill signals can be found on the kill man page.

Some of the more commonly used signals:
1       HUP (hang up)
2       INT (interrupt)
3       QUIT (quit)
6       ABRT (abort)
9       KILL (non-catchable, non-ignorable kill)
14      ALRM (alarm clock)
15      TERM (software termination signal)

So if we had used that instead, we would have seen this in the first shell.

myusername@someserver:~$ Killed: 9
$

Questions?

If you need clarification on this tip, just ask in the comments below. I’d love to help! And remember, if you have questions about bash and other shell commands, let me know, and I might cover that topic next.