--- title: "Level Up Your Shell Game" date: 2013-10-24T00:00:00+00:00 draft: false needs_review: true canonical_url: https://www.viget.com/articles/level-up-your-shell-game/ --- The Viget dev team was recently relaxing by the fireplace, sipping a fine cognac out of those fancy little glasses, when the conversation turned (as it often does) to the Unix command line. We have good systems in place for sharing Ruby techniques ([pull request code reviews](https://viget.com/extend/developer-ramp-up-with-pull-requests)) and [Git tips](https://viget.com/extend/a-gaggle-of-git-tips), but everyone seemed to have a simple, useful command-line trick or two that the rest of the team had never encountered. Here are a few of our favorites: - [Keyboard Shortcuts](https://viget.com/extend/level-up-your-shell-game#keyboard-shortcuts) - [Aliases](https://viget.com/extend/level-up-your-shell-game#aliases) - [History Expansions](https://viget.com/extend/level-up-your-shell-game#history-expansions) - [Argument Expansion](https://viget.com/extend/level-up-your-shell-game#argument-expansion) - [Customizing `.inputrc`](https://viget.com/extend/level-up-your-shell-game#customizing-inputrc) - [Viewing Processes on a Given Port with `lsof`](https://viget.com/extend/level-up-your-shell-game#viewing-processes-on-a-given-port-with-lsof) - [SSH Configuration](https://viget.com/extend/level-up-your-shell-game#ssh-configuration) - [Invoking Remote Commands with SSH](https://viget.com/extend/level-up-your-shell-game#invoking-remote-commands-with-ssh) Ready to get your ![](https://github.global.ssl.fastly.net/images/icons/emoji/neckbeard.png){.no-border align="top" height="24" style="display: inline; vertical-align: top; width: 24px !important; height: 24px !important;"} on? Good. Let's go. ## Keyboard Shortcuts [**Mike:**](https://viget.com/about/team/mackerman) I recently discovered a few simple Unix keyboard shortcuts that save me some time: Shortcut Result ---------------------- ---------------------------------------------------------------------------- `ctrl + u` Deletes the portion of your command **before** the current cursor position `ctrl + w` Deletes the **word** preceding the current cursor position `ctrl + left arrow` Moves the cursor to the **left by one word** `ctrl + right arrow` Moves the cursor to the **right by one word** `ctrl + a` Moves the cursor to the **beginning** of your command `ctrl + e` Moves the cursor to the **end** of your command Thanks to [Lawson Kurtz](https://viget.com/about/team/lkurtz) for pointing out the beginning and end shortcuts ## Aliases [**Eli:**](https://viget.com/about/team/efatsi) Sick of typing `bundle exec rake db:test:prepare` or other long, exhausting lines of terminal commands? Me too. Aliases can be a big help in alleviating the pain of typing common commands over and over again. They can be easily created in your `~/.bash_profile` file, and have the following syntax: alias gb="git branch" I've got a whole slew of git and rails related ones that are fairly straight-forward: alias ga="git add .; git add -u ." alias glo='git log --pretty=format:"%h%x09%an%x09%s"' alias gpro="git pull --rebase origin" ... alias rs="rails server" And a few others I find useful: alias editcommit="git commit --amend -m" alias pro="cd ~/Desktop/Projects/" alias s.="subl ." alias psgrep="ps aux | grep" alias cov='/usr/bin/open -a "/Applications/Google Chrome.app" coverage/index.html' If you ever notice yourself typing these things out over and over, pop into your `.bash_profile` and whip up some of your own! If `~/.bash_profile` is hard for you to remember like it is for me, nothing an alias can't fix: `alias editbash="open ~/.bash_profile"`. **Note**: you'll need to open a new Terminal window for changes in `~/.bash_profile` to take place. ## History Expansions [**Chris:**](https://viget.com/about/team/cjones) Here are some of my favorite tricks for working with your history. **`!!` - previous command** How many times have you run a command and then immediately re-run it with `sudo`? The answer is all the time. You could use the up arrow and then [Mike](https://viget.com/about/team/mackerman)'s `ctrl-a` shortcut to insert at the beginning of the line. But there's a better way: `!!` expands to the entire previous command. Observe: $ rm path/to/thing Permission denied $ sudo !! sudo rm path/to/thing **`!$` - last argument of the previous command** How many times have you run a command and then run a different command with the same argument? The answer is all the time. Don't retype it, use `!$`: $ mkdir path/to/thing $ cd !$ cd path/to/thing **`!` - most recent command starting with** Here's a quick shortcut for running the most recent command that *starts with* the provided string: $ rake db:migrate:reset db:seed $ rails s $ !rake # re-runs that first command **`!` - numbered command** All of your commands are stored in `~/.bash_history`, which you can view with the `history` command. Each entry has a number, and you can use `!` to run that specific command. Try it with `grep` to filter for specific commands: $ history | grep heroku 492 heroku run rake search:reindex -r production 495 heroku maintenance:off -r production 496 heroku run rails c -r production $ !495 This technique is perfect for an alias: $ alias h?="history | grep" $ h? heroku 492 heroku run rake search:reindex -r production 495 heroku maintenance:off -r production 496 heroku run rails c -r production $ !495 Sweet. ## Argument Expansion [**Ryan:**](https://viget.com/about/team/rfoster) For commands that take multiple, similar arguments, you can use `{old,new}` to expand one argument into two or more. For example: mv app/models/foo.rb app/models/foobar.rb can be mv app/models/{foo,foobar}.rb or even mv app/models/foo{,bar}.rb ## Customizing .inputrc {#customizing-inputrc} [**Brian:**](https://viget.com/about/team/blandau) One of the things I have found to be a big time saver when using my terminal is configuring keyboard shortcuts. Luckily if you're still using bash (which I am), you can configure shortcuts and use them in a number of other REPLs that all use readline. You can [configure readline keyboard shortcuts by editing your `~/.inputrc` file](http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC9). Each line in the file defines a shortcut. It's made up of two parts, the key sequence, and the command or macro. Here are three of my favorites: 1. `"\ep": history-search-backward`: This will map to escape-p and will allow you to search for completions to the current line from your history. For instance, it will allow you to type "`git`" into your shell and then hit escape-p to cycle through all the git commands you have used recently looking for the correct completion. 2. `"\t": menu-complete`: I always hated that when I tried to tab complete something and then I'd get a giant list of possible completions. By adding this line you can instead use tab to cycle through all the possible completions stopping on which ever one is the correct one. 3. `"\C-d": kill-whole-line`: There's a built-in key command for killing a line after the cursor (control-k), but no way to kill the whole line. This solves that. After adding this to your `.inputrc` just type control-d from anywhere on the line and the whole line is gone and you're ready to start fresh. Don't like what I mapped these commands to? Feel free to use different keyboard shortcuts by changing that first part in quotes. There's a lot more you can do, just check out [all the commands you can assign](http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC13) or create your own macros. ## Viewing Processes on a Given Port with lsof [**Zachary:**](https://viget.com/about/team/zporter) When working on projects, I occassionally need to run the application on port 80. While I could use a tool like [Pow](http://pow.cx/) to accomplish this, I choose to use [Passenger Standalone](http://www.modrails.com/documentation/Users%20guide%20Standalone.html). However, when trying to start Passenger on port 80, I will get a response that looks something like "The address 0.0.0.0:80 is already in use by another process". To easily view all processes communicating over port 80, I use [`lsof`](http://linux.die.net/man/8/lsof) like so: sudo lsof -i :80 From here, I can pin-point who the culprit is and kill it. ## SSH Configuration [**Patrick:**](https://viget.com/about/team/preagan) SSH is a simple tool to use when you need shell access to a remote server. Everyone is familiar with the most basic usage: $ ssh production.host Command-line options give you control over more options such as the user and private key file that you use to authenticate: $ ssh -l www-data -i /Users/preagan/.ssh/viget production.host However, managing these options with the command-line is tedious if you use different private keys for work-related and personal servers. This is where your local `.ssh/config` file can help -- by specifying the host that you connect to, you can set specific options for that connection: # ~/.ssh/config Host production.host User www-data IdentityFile /Users/preagan/.ssh/viget Now, simply running `ssh production.host` will use the correct username and private key when authenticating. Additionally, services that use SSH as the underlying transport mechanism will honor these settings -- you can use this with Github to send an alternate private key just as easily: Host github.com IdentityFile /Users/preagan/.ssh/github **Bonus Tip** This isn't limited to just setting host-specific options, you can also use this configuration file to create quick aliases for hosts that aren't addressable by DNS: Host prod Hostname 192.168.1.1 Port 6000 User www-data IdentityFile /Users/preagan/.ssh/production-key All you need to do is run `ssh prod` and you're good to go. For more information on what settings are available, check out the manual ([`man ssh_config`](http://linux.die.net/man/5/ssh_config)). ## Invoking Remote Commands with SSH [**David**:](https://viget.com/about/team/deisinger) You're already using SSH to launch interactive sessions on your remote servers, but DID YOU KNOW you can also pass the commands you want to run to the `ssh` program and use the output just like you would a local operation? For example, if you want to pull down a production database dump, you could: 1. `ssh` into your production server 2. Run `mysqldump` to generate the data dump 3. Run `gzip` to create a compressed file 4. Log out 5. Use `scp` to grab the file off the remote server Or! You could use this here one-liner: ssh user@host.com "mysqldump -u db_user -h db_host -pdb_password db_name | gzip" > production.sql.gz Rather than starting an interactive shell, you're logging in, running the `mysqldump` command, piping the result into `gzip`, and then taking the result and writing it to a local file. From there, you could chain on decompressing the file, importing it into your local database, etc. **Bonus tip:** store long commands like this in [boom](https://github.com/holman/boom) for easy recall. ------------------------------------------------------------------------ Well, that's all we've got for you. Hope you picked up something useful along the way. What are your go-to command line tricks? Let us know in the comments.