Nearly all shells have support for tab completion. At a minimum for completing file & directory names, though some even tab-complete based on which commands you're running. Some examples:
$ ls [TAB]
Gemfile app/ connectors.rb public/
Gemfile.lock bin/ db/ spec/
README.rdoc config/ lib/ tmp/
Rakefile config.ru log/ vendor/
Modern shells (like zsh) will tab complete with more appropriate choices. For example if you're trying to cd
instead of ls
, only show directories:
$ cd [TAB]
app/ config/ lib/ public/ tmp/
bin/ db/ log/ spec/ vendor/
So don't manually type out file names or long paths. There's a better way. Another plug for zsh: fuzzy matching!
$ vi db/migrate/speaker[TAB]
$ vi db/migrate/20131117003047_create_speakers.rb
With the right shell setup tab completion even works great for non-shell commands (like git):
$ git checkout [TAB]
FETCH_HEAD origin/inquiry-seeds-data
HEAD origin/jma_program
ORIG_HEAD origin/last-question-next
add-admire-people-text origin/layout-template
If you didn't know it yet, your shell supports its own language! You can write scripts in Bash/sh (GNU Bourne-Again Shell/Bourne Shell). There are books on this of course. Shell scripting remains popular because of its ubiquity. You can expect nearly every *nix system to support sh
scripts.
Here's a sample script to whet your appetite:
for k in `git branch | sed s/^..//`;
do
echo `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";
done | sort
Any idea what the above script does? Something with git branches, right? Well it actually prints your local branches in order of most recent commit! HOW NEAT IS THAT?? Here's some sample output:
2013-10-16 21:19:37 -0500 7 weeks ago jma_program
2013-11-11 17:17:51 -0600 3 weeks ago layout-template
2013-11-12 09:59:37 -0600 3 weeks ago current-program-fixes
2013-11-15 21:45:06 -0600 3 weeks ago program-fixes
2013-11-16 16:12:09 -0600 3 weeks ago workzone_fix
2013-11-23 10:55:00 -0600 11 days ago master
If you review the above script carefully, you'll notice it uses 3! different programs, git
, sed
and sort
(echo is a built in shell command, so it doesn't count). You'll find that shell scripts tend to be built this way, glueing together a number of separate programs to make something more useful.
You might have noticed the for in
loop in the sample script. See that k
variable being re-used inside the loop as $k
? Thats an example of using a variable in the shell. You can set your own right on the command line:
$ foo=bar
$ echo $foo
bar
If you want your variable to be available to any other programs you run within your shell (a subprocess) export the variable:
$ export foo
$ export another="this is a longer value"
You're probably familiar with exporting variables for things like API keys that you don't want to store in your source code.
In fact, if you haven't realized yet, when you open a new terminal...YOU'RE IN A REPL! (read–eval–print loop -- remember, irb
that's also a REPL)
Redirection & pipes are the connectors of shell scripting. Since we tend to rely separate programs we need a way to connect them up and pass data from one to the other.
The easiest way to do that is with the |
(pipe) character. The |
chains two commands together by connecting the STDOUT of the first to the STDIN of the second. For example:
ls -l | sed -e "s/[aeio]/u/g"
In the above the output of ls -l
is fed into the sed
program. sed
is a "stream editor", allowing you to modify a stream of characters as it passes through. In the above example, we're replacing aeio with the character u. Here's some sample output with and without piping to sed
:
$ ls -l
total 3216
-rw-r--r-- 1 nate staff 1279 Sep 16 20:26 Gemfile
-rw-r--r-- 1 nate staff 4183 Sep 4 21:34 Gemfile.lock
-rw-r--r-- 1 nate staff 2031 Aug 9 14:31 README.md
-rw-r--r-- 1 nate staff 258 Aug 5 10:16 Rakefile
drwxr-xr-x 9 nate staff 306 Sep 4 19:09 app
drwxr-xr-x 5 nate staff 170 Sep 10 14:26 bin
-rw-r--r-- 1 nate staff 134 Dec 4 08:43 branches.sh
$ ls -l | sed -e "s/[aeio]/u/g
-rw-r--r-- 1 nutu stuff 1279 Sup 16 20:26 Gumfulu
-rw-r--r-- 1 nutu stuff 4183 Sup 4 21:34 Gumfulu.luck
-rw-r--r-- 1 nutu stuff 2031 Aug 9 14:31 README.md
-rw-r--r-- 1 nutu stuff 258 Aug 5 10:16 Rukufulu
drwxr-xr-x 9 nutu stuff 306 Sup 4 19:09 upp
drwxr-xr-x 5 nutu stuff 170 Sup 10 14:26 bun
-rw-r--r-- 1 nutu stuff 134 Duc 4 08:43 brunchus.sh
Redirection can sometimes serve as a stdin for a pipe, but most often it's used to redirect output to a file, instead of another program.
$ ls /Users/*ael > users_probably_called_michael.txt
Instead of printing to stdout in the above example, we're redirecting the output to a file.
Redirection with a single >
overwrites any existing destination, a double >>
appends to the file:
$ echo "Decorative Doggie Doors" >> ~/ideas.txt
Remember stdin, stderr and stdout from the *nix challenge? You redirect each one as you wish.
# redirect stdout to file
ls /Users/*ael 1> list.txt
# redirect stderr to file
ls /Users/*ael 2> errors.txt
# redirect both stdout and stderr
ls /Users/*ael &> errors.txt
If you don't specify a number or &, the default is to redirect stdout. You can even redirect from one output to another!
# redirect stderr to stdout
ls 2>&1 /Users/*ael
You can also redirect to the stdin of a process. Here we redirect a subshell's output to the wc
command:
$ wc <(curl http://www.google.com 2> /dev/null)
16 304 10866 /dev/fd/11
Now we know how many words are in google.com's source: 304.
You can run multiple programs on a single line by separating them with a colon character:
$ echo "Hi"; ls /Users
Hi
Shared nate
You can conditionally run the next program if the previous one doesn't return an error status with &&
$ ls /Users/nonexistent && echo "You won a million dollars"
ls: /Users/nonexistent: No such file or directory
||
is also available, which runs the second command only if the first fails:
$ ls /Users/new_guy || mkdir /Users/new_guy
-
diff <(curl http://www.google.com | tidy) <(curl http://www.google.fr |tidy)
-
git log -p
-
git diff branch..master
-
cd -
-
cd ~/Documents
-
git log --pretty=format:"%h %s" --graph
-
tail -f
-
grep
-
awk
-
git branch -v
-
-h --help -v -vv --version
-
tree -L 2
-
xargs
-
wc -l
-
ls **/jpg > jpg.txt
-
vi **/database.yml
-
!ls or !vi
-
man ls
-
grep -i -V -C -r
-
Symbolic links
-
Esc .
-
ps aux
-
hover in chrome JS debugger
-
JSON extension for Chrome