index.md (11288B)
1 --- 2 title: "Level Up Your Shell Game" 3 date: 2013-10-24T00:00:00+00:00 4 draft: false 5 canonical_url: https://www.viget.com/articles/level-up-your-shell-game/ 6 --- 7 8 The Viget dev team was recently relaxing by the fireplace, sipping a 9 fine cognac out of those fancy little glasses, when the conversation 10 turned (as it often does) to the Unix command line. We have good systems 11 in place for sharing Ruby techniques ([pull request code 12 reviews](https://viget.com/extend/developer-ramp-up-with-pull-requests)) 13 and [Git tips](https://viget.com/extend/a-gaggle-of-git-tips), but 14 everyone seemed to have a simple, useful command-line trick or two that 15 the rest of the team had never encountered. Here are a few of our 16 favorites: 17 18 - [Keyboard 19 Shortcuts](#keyboard-shortcuts) 20 - [Aliases](#aliases) 21 - [History 22 Expansions](#history-expansions) 23 - [Argument 24 Expansion](#argument-expansion) 25 - [Customizing 26 `.inputrc`](#customizing-inputrc) 27 - [Viewing Processes on a Given Port with 28 `lsof`](#viewing-processes-on-a-given-port-with-lsof) 29 - [SSH 30 Configuration](#ssh-configuration) 31 - [Invoking Remote Commands with 32 SSH](#invoking-remote-commands-with-ssh) 33 34 Ready to get your {{<dither neckbeard.png "" "inline">}}Grinning caricature with messy hair, glasses, and a scruffy beard.{{</dither>}} on? Good. Let's go. 35 36 ## Keyboard Shortcuts 37 38 [**Mike:**](https://viget.com/about/team/mackerman) I recently 39 discovered a few simple Unix keyboard shortcuts that save me some time: 40 41 Shortcut | Result 42 ---------------------|----------------------------------------------------------------------------- 43 `ctrl + u` | Deletes the portion of your command **before** the current cursor position 44 `ctrl + w` | Deletes the **word** preceding the current cursor position 45 `ctrl + left arrow` | Moves the cursor to the **left by one word** 46 `ctrl + right arrow` | Moves the cursor to the **right by one word** 47 `ctrl + a` | Moves the cursor to the **beginning** of your command 48 `ctrl + e` | Moves the cursor to the **end** of your command 49 50 Thanks to [Lawson Kurtz](https://viget.com/about/team/lkurtz) for 51 pointing out the beginning and end shortcuts 52 53 ## Aliases 54 55 [**Eli:**](https://viget.com/about/team/efatsi) Sick of typing 56 `bundle exec rake db:test:prepare` or other long, exhausting lines of 57 terminal commands? Me too. Aliases can be a big help in alleviating the 58 pain of typing common commands over and over again. 59 60 They can be easily created in your `~/.bash_profile` file, and have the 61 following syntax: 62 63 alias gb="git branch" 64 65 I've got a whole slew of git and rails related ones that are fairly 66 straight-forward: 67 68 alias ga="git add .; git add -u ." 69 alias glo='git log --pretty=format:"%h%x09%an%x09%s"' 70 alias gpro="git pull --rebase origin" 71 ... 72 alias rs="rails server" 73 74 And a few others I find useful: 75 76 alias editcommit="git commit --amend -m" 77 alias pro="cd ~/Desktop/Projects/" 78 alias s.="subl ." 79 alias psgrep="ps aux | grep" 80 alias cov='/usr/bin/open -a "/Applications/Google Chrome.app" coverage/index.html' 81 82 If you ever notice yourself typing these things out over and over, pop 83 into your `.bash_profile` and whip up some of your own! If 84 `~/.bash_profile` is hard for you to remember like it is for me, nothing 85 an alias can't fix: `alias editbash="open ~/.bash_profile"`. 86 87 **Note**: you'll need to open a new Terminal window for changes in 88 `~/.bash_profile` to take place. 89 90 ## History Expansions 91 92 [**Chris:**](https://viget.com/about/team/cjones) Here are some of my 93 favorite tricks for working with your history. 94 95 **`!!` - previous command** 96 97 How many times have you run a command and then immediately re-run it 98 with `sudo`? The answer is all the time. You could use the up arrow and 99 then [Mike](https://viget.com/about/team/mackerman)'s `ctrl-a` shortcut 100 to insert at the beginning of the line. But there's a better way: `!!` 101 expands to the entire previous command. Observe: 102 103 $ rm path/to/thing 104 Permission denied 105 $ sudo !! 106 sudo rm path/to/thing 107 108 **`!$` - last argument of the previous command** 109 110 How many times have you run a command and then run a different command 111 with the same argument? The answer is all the time. Don't retype it, use 112 `!$`: 113 114 $ mkdir path/to/thing 115 $ cd !$ 116 cd path/to/thing 117 118 **`!<string>` - most recent command starting with** 119 120 Here's a quick shortcut for running the most recent command that *starts 121 with* the provided string: 122 123 $ rake db:migrate:reset db:seed 124 $ rails s 125 $ !rake # re-runs that first command 126 127 **`!<number>` - numbered command** 128 129 All of your commands are stored in `~/.bash_history`, which you can view 130 with the `history` command. Each entry has a number, and you can use 131 `!<number>` to run that specific command. Try it with `grep` to filter 132 for specific commands: 133 134 $ history | grep heroku 135 492 heroku run rake search:reindex -r production 136 495 heroku maintenance:off -r production 137 496 heroku run rails c -r production 138 $ !495 139 140 This technique is perfect for an alias: 141 142 $ alias h?="history | grep" 143 $ h? heroku 144 492 heroku run rake search:reindex -r production 145 495 heroku maintenance:off -r production 146 496 heroku run rails c -r production 147 $ !495 148 149 Sweet. 150 151 ## Argument Expansion 152 153 [**Ryan:**](https://viget.com/about/team/rfoster) For commands that take 154 multiple, similar arguments, you can use `{old,new}` to expand one 155 argument into two or more. For example: 156 157 mv app/models/foo.rb app/models/foobar.rb 158 159 can be 160 161 mv app/models/{foo,foobar}.rb 162 163 or even 164 165 mv app/models/foo{,bar}.rb 166 167 ## Customizing .inputrc 168 169 [**Brian:**](https://viget.com/about/team/blandau) One of the things I 170 have found to be a big time saver when using my terminal is configuring 171 keyboard shortcuts. Luckily if you're still using bash (which I am), you 172 can configure shortcuts and use them in a number of other REPLs that all 173 use readline. You can [configure readline keyboard shortcuts by editing 174 your `~/.inputrc` 175 file](http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC9). 176 Each line in the file defines a shortcut. It's made up of two parts, the 177 key sequence, and the command or macro. Here are three of my favorites: 178 179 1. `"\ep": history-search-backward`: This will map to escape-p and will 180 allow you to search for completions to the current line from your 181 history. For instance, it will allow you to type "`git`" into your 182 shell and then hit escape-p to cycle through all the git commands 183 you have used recently looking for the correct completion. 184 2. `"\t": menu-complete`: I always hated that when I tried to tab 185 complete something and then I'd get a giant list of possible 186 completions. By adding this line you can instead use tab to cycle 187 through all the possible completions stopping on which ever one is 188 the correct one. 189 3. `"\C-d": kill-whole-line`: There's a built-in key command for 190 killing a line after the cursor (control-k), but no way to kill the 191 whole line. This solves that. After adding this to your `.inputrc` 192 just type control-d from anywhere on the line and the whole line is 193 gone and you're ready to start fresh. 194 195 Don't like what I mapped these commands to? Feel free to use different 196 keyboard shortcuts by changing that first part in quotes. There's a lot 197 more you can do, just check out [all the commands you can 198 assign](http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC13) 199 or create your own macros. 200 201 ## Viewing Processes on a Given Port with lsof 202 203 [**Zachary:**](https://viget.com/about/team/zporter) When working on 204 projects, I occasionally need to run the application on port 80. While 205 I could use a tool like [Pow](http://pow.cx/) to accomplish this, I 206 choose to use [Passenger 207 Standalone](http://www.modrails.com/documentation/Users%20guide%20Standalone.html). 208 However, when trying to start Passenger on port 80, I will get a 209 response that looks something like "The address 0.0.0.0:80 is already in 210 use by another process". To easily view all processes communicating over 211 port 80, I use [`lsof`](http://linux.die.net/man/8/lsof) like so: 212 213 sudo lsof -i :80 214 215 From here, I can pin-point who the culprit is and kill it. 216 217 ## SSH Configuration 218 219 [**Patrick:**](https://viget.com/about/team/preagan) SSH is a simple 220 tool to use when you need shell access to a remote server. Everyone is 221 familiar with the most basic usage: 222 223 $ ssh production.host 224 225 Command-line options give you control over more options such as the user 226 and private key file that you use to authenticate: 227 228 $ ssh -l www-data -i /Users/preagan/.ssh/viget production.host 229 230 However, managing these options with the command-line is tedious if you 231 use different private keys for work-related and personal servers. This 232 is where your local `.ssh/config` file can help -- by specifying the 233 host that you connect to, you can set specific options for that 234 connection: 235 236 # ~/.ssh/config 237 Host production.host 238 User www-data 239 IdentityFile /Users/preagan/.ssh/viget 240 241 Now, simply running `ssh production.host` will use the correct username 242 and private key when authenticating. Additionally, services that use SSH 243 as the underlying transport mechanism will honor these settings -- you 244 can use this with Github to send an alternate private key just as 245 easily: 246 247 Host github.com 248 IdentityFile /Users/preagan/.ssh/github 249 250 **Bonus Tip** 251 252 This isn't limited to just setting host-specific options, you can also 253 use this configuration file to create quick aliases for hosts that 254 aren't addressable by DNS: 255 256 Host prod 257 Hostname 192.168.1.1 258 Port 6000 259 User www-data 260 IdentityFile /Users/preagan/.ssh/production-key 261 262 All you need to do is run `ssh prod` and you're good to go. For more 263 information on what settings are available, check out the manual 264 ([`man ssh_config`](http://linux.die.net/man/5/ssh_config)). 265 266 ## Invoking Remote Commands with SSH 267 268 [**David**:](https://viget.com/about/team/deisinger) You're already 269 using SSH to launch interactive sessions on your remote servers, but DID 270 YOU KNOW you can also pass the commands you want to run to the `ssh` 271 program and use the output just like you would a local operation? For 272 example, if you want to pull down a production database dump, you could: 273 274 1. `ssh` into your production server 275 2. Run `mysqldump` to generate the data dump 276 3. Run `gzip` to create a compressed file 277 4. Log out 278 5. Use `scp` to grab the file off the remote server 279 280 Or! You could use this here one-liner: 281 282 ssh [email protected] "mysqldump -u db_user -h db_host -pdb_password db_name | gzip" > production.sql.gz 283 284 Rather than starting an interactive shell, you're logging in, running 285 the `mysqldump` command, piping the result into `gzip`, and then taking 286 the result and writing it to a local file. From there, you could chain 287 on decompressing the file, importing it into your local database, etc. 288 289 **Bonus tip:** store long commands like this in 290 [boom](https://github.com/holman/boom) for easy recall. 291 292 ------------------------------------------------------------------------ 293 294 Well, that's all we've got for you. Hope you picked up something useful 295 along the way. What are your go-to command line tricks? Let us know in 296 the comments.