Skip to content

Instantly share code, notes, and snippets.

@jaymcgavren
Created October 27, 2012 19:15
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jaymcgavren/3965735 to your computer and use it in GitHub Desktop.
Save jaymcgavren/3965735 to your computer and use it in GitHub Desktop.

Description

In this episode, Jay McGavren shares some of his favorite tricks for working in the shell. No unreadable sed or awk scripts here. Just simple, solid tips you can use every day, including time savers with find, less, ssh, and command-line Ruby.

Why learn shell commands when there's an IDE?

http://programmer.97things.oreilly.com/wiki/index.php/The_Unix_Tools_Are_Your_Friends

What if you're on Windows?

http://railsinstaller.org/

find

exec

$ find myproject -name ".svn" -exec rm -rf "{}" \;

The exec option is particularly useful in combination with these commands:

  • cat (Use with -print if you want the file name as well)
  • grep --with-filename
  • rm (For pete's sake, use -print to see what files get found first!)

less

prompt

The default prompt shows only the current file name:

...
  tellus. Sed eget metus. Donec sapien justo, varius at, adipiscing quis, euismod
  sed, orci. Quisque vel pede non dui adipiscing ullamcorper. Nulla facilisi.
  Fusce sapien.

You can permanently set the -P option via the $LESS environment variable for a more informative prompt:

$ export LESS='-P%f (%i/%m) Line %lt/%L'
...
  tellus. Sed eget metus. Donec sapien justo, varius at, adipiscing quis, euismod
  sed, orci. Quisque vel pede non dui adipiscing ullamcorper. Nulla facilisi.
  Fusce sapien.

ack

TODO: brew install?

--all-types

ssh

~/.ssh/config

  • Host: shortcut
  • HostName: full address
  • User: username to use

non-interactive remote command

  • piping back to local command

cb

My interface to pbcopy/pbpaste/xclip/xclip -o

STDIN is tty?

Ruby

hashbang

data loop

DATA.readlines.map{|l| l.chomp}.each do |line|
end
__END__

-e

$ ruby -e "f = File.open(ARGV[0]); while line = f.gets;\
 print line.chomp; end" email.txt

$ ruby -e "while line = gets; print line.chomp; end" email.txt

-n

$ ruby -ne "print chomp" email.txt

-p

$ ruby -pe "chomp" email.txt

$ ruby -pe "chomp; gsub /Java/, '.Net'" email.txt

References

Unix utilities: http://unixhelp.ed.ac.uk

find: http://unixhelp.ed.ac.uk/CGI/man-cgi?find cat: http://unixhelp.ed.ac.uk/CGI/man-cgi?cat grep: http://unixhelp.ed.ac.uk/CGI/man-cgi?grep rm: http://unixhelp.ed.ac.uk/CGI/man-cgi?rm less: http://unixhelp.ed.ac.uk/CGI/man-cgi?less

Ack: http://betterthangrep.com/

Why Unix: http://programmer.97things.oreilly.com/wiki/index.php/The_Unix_Tools_Are_Your_Friends

Cygwin: http://www.cygwin.com/

Rails Installer: http://railsinstaller.org/

cb clipboard utility: https://github.com/jaymcgavren/dotfiles/blob/master/bin/cb

diff

-b, --ignore-space-change

$ diff new_guy.rb fixed.rb 
2,4c2,4
< 	def herp
< 		"derp"
< 	end
---
>   def herp
>     "get off my lawn"
>   end

$ diff -b new_guy.rb fixed.rb 
3c3
< 		"derp"
---
>     "get off my lawn"

-r, --recursive

$ diff -r myproj myproj.bak
...
diff -r 
myproj/config/db.properties
myproj.bak/config/db.properties
4a5,10
> myproj.dbname=mydev
8,9c14
< myproj.dbname=mysandbox

old_diff, new_diff

old_diff

#!/bin/sh
cat > $HOME/.old_diff

new_diff

#!/bin/sh
diff -b $HOME/.old_diff -

Usage

$ git log
commit 8bb972da777abd9d863d0ca0a019ba8d6d70bfa7
Author: Jay McGavren <jay@initech.com>
Date:   Tue Mar 6 21:39:37 2012 -0700

    FTFY.

commit 2ff7ba4f7c549cdd3bf34372c9594b17cd02619c
Author: New Guy <newguy@initech.com>
Date:   Tue Mar 6 21:38:09 2012 -0700

    Herp derp!

$ git log | old_diff

$ git log | new_diff
0a1,6
> commit 87b9bc7a1d39021cef3e7856714e958ccc2103d1
> Author: New Guy <newguy@initech.com>
> Date:   Tue Mar 6 21:42:26 2012 -0700
> 
>     I like tabs and Jay is stoopid!

$ git log | new_diff
0a1,12
> commit 41fa7b5a91643f13e2b6fbad2768be877b66885e
> Author: Jay McGavren <jay@initech.com>
> Date:   Tue Mar 6 21:57:47 2012 -0700
> 
>     Jerk. I'm giving your stapler to Milton.
> 
> commit 87b9bc7a1d39021cef3e7856714e958ccc2103d1
> Author: New Guy <newguy@initech.com>
> Date:   Tue Mar 6 21:42:26 2012 -0700
> 
>     I like tabs and Jay is stoopid!

xargs

$ ls -1
1.txt
2.txt
3.txt

Echo file names:

$ ls -1 | xargs echo "I found some files:"
I found some files: 1.txt 2.txt 3.txt

-1 is actually the default when piping:

$ ls | xargs echo "I found some files:"

Send all .txt files to "less":

$ find . -name "*.txt" | xargs less

Send .log files to "less", newest first:

$ ls -t *.log | xargs less

Delete the 5 oldest .log files:

$ ls -t *.log | tail -n 5 | xargs rm

sort

cb | sort | old_diff cb | sort | new_diff cb | sort | uniq

-n

du -k . | sort -n

Prompt

The default prompt:

-bash-3.2$

Set the $PS1 environment variable to change your prompt:

$ export PS1='> '
> 
> 
> 

This prompt uses substitution to display the current login name, host, working directory, and superuser status ($ normally, # for root):

$ export PS1='\u@\h:\w\n\$ '
jay@dandelion:~/Projects/shell
$

This one uses interpolation to include the date and time. (Use single quotes, not double quotes!)

$ export PS1='$(date +%Y%m%d_%H%M%S) \$ '
20120309_045655 $ 
20120309_045725 $ 

See the PROMPTING section of the bash manpage for more details.

$ man bash

history

Environment setup:

export HISTFILESIZE=10000
export HISTSIZE=10000

#Multiple shells may overwrite each others' history.
#This fixes that.
shopt -s histappend

#Make shells write to history immediately.
#Normally they write only on exit.
export PROMPT_COMMAND='history -a'

Repeat the prior command

$ echo "This bears repeating."
This bears repeating.
$ !!
echo "This bears repeating."
This bears repeating.

Repeat a numbered command from history:

$ history | tail
...
2207  l $HISTFILE
2208  echo "This bears repeating."
2209  history | tail
$ !2208
echo "This bears repeating."
This bears repeating.

See HISTORY EXPANSION in the Bash manpage for more.

Ctrl-r: reverse-search-history

dotfiles

.profile

  • Sourced for all login shells, be they zsh or bash.
  • Use for environment stuff:
    • $PATH
    • $RUBYLIB
    • $JAVA_HOME

.bash_profile

  • Sourced only for bash.
  • bash-specific stuff:
    • PS1 prompt
    • bash_completion

GitHub

  • Make (or fork) a dotfiles repo

  • Check out to ~/dotfiles

    $ cd ~ $ git clone git@github.com:jaymcgavren/dotfiles.git

  • Source dotfiles/profile from ~/.profile:

    if [ -f $HOME/dotfiles/profile ]; then . $HOME/dotfiles/profile fi

  • Source dotfiles/bash_profile from ~/.bash_profile:

    if [ -f $HOME/dotfiles/bash_profile ]; then . $HOME/dotfiles/bash_profile fi

  • I keep a Ruby playground in a subdir and add it to $RUBYLIB:

    export RUBYLIB=${HOME}/dotfiles/ruby/lib:${RUBYLIB}

References

ANSI colors: http://en.wikipedia.org/wiki/ANSI_escape_code

Bash history tips: http://mywiki.wooledge.org/BashFAQ/088

Zach Holman on dotfiles: http://zachholman.com/2010/08/dotfiles-are-meant-to-be-forked/

My dotfiles: https://github.com/jaymcgavren/dotfiles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment