Do not fear the command line

DZone 's Guide to

Do not fear the command line

· Agile Zone ·
Free Resource

As you know I love ssh, but I also love the command line tools  in general.

However, many times I see ordinary people (non-programmers, but even programmers) struggle with entering textual commands. The reality is that the cli should not be a pain to use: this is true only when it has been built in the wrong way. For example, try repeating multiple-line commands in mysqladmin or in Matlab's shell; those are environments where the fear of having to re-enter commands is justified.

However there are beautiful environments too, where the command line gives you a productivity you can only dream of on point'n'click interfaces. Repeating command is actually simpler than clicking around multiple times.

A disclaimer: I use bash on Linux. Maybe I'm including some Ubuntu-specific information, but I think most of this article applies to every Linux or even every Unix-like system.

The basics (you know what a terminal is, right?)

Your .bashrc file will be executed at each terminal you open: it's handy for including some setup code. You don't usually see this file from a GUI because it's hidden: each file starting with a dot (.) is.

You can use the source filename command to include other files, if you do not want to put everything inside .bashrc. With ~ you can refer to your home directory.

Don't backslash: you can easily specify a "strings with spaces" in this manner. That's the only sane way to include commit messages directly from the command line instead of opening an editor.

Command can be nested: for example, you can just quote a command in backticks and use it as the argument of another command: echo `echo Hello`.

* is a wildcard: it means that if you include it in paths, every character or string will be matched in its place.

| is the pipe: it allows you to pick the output of a command and using it as the input of another one: echo Hello | grep Hello

You don't have to write commands more than zero or one times

Let's tackle now that issue of having to rewrite commands. If you go in your /etc/inputrc, or you create a ~/.inputrc file, you can put (or uncomment if they are already there) these lines in it:

"\e[5~": history-search-backward
"\e[6~": history-search-forward

Now open a new terminal, and when you push PgUp or PgDown you will navigate in the history with the part of command you have already written. For example, ec<PgUp> looks for all the echo commands you have entered.

And why not use a very large history so that you could find that command you typed in 2004? Include this in your .bashrc:


And maybe, you can also tell the various terminals you open to append instead of overwriting the history of each other.

shopt -s histappend

Now that we can avoid writing already typed commands, why don't we avoid writing even new ones?

Set up autocompletion by sourcing the right system-level file:

source /etc/bash_completion

if you're not already doing it. Now when you type ec<Tab> the command will be completed, or if more than one command starts with ec, you will be shown a list. It works with paths too:

cat f<Tab> 

will print a file beginning with f. And paths are usually tailored for the current program, so if you type:

ssh D<Tab>

it will also looks for hosts whose name begins with D, and not only files.


git checkout a<Tab>

will tell you which branches start with a, not which files.

Maybe we have very long commands, so let's alias it to something simple to type:

alias agi='sudo apt-get install'

Now, agi vim will let you install the vim package.

Messing with PATH

You can add your own directory of scripts, which will became available as commands just as grep and find:



However, there are already many powerful commands available. For example grep is a must-know utility that is used to search for some text into files:

cat file.txt | grep pattern

will output all the lines of file.txt where pattern is contained. The simplest pattern is a string, but regular expressions can be included (the string does the job 90% of the time).

grep -r pattern *.txt

will search pattern in all *.txt files.
Other options are -i for case-insensitive matching and -l for displaying only one time each file. With -n the line number is displayed, and with -A and -B you can specify now many lines to show after and before a match (by default, 0).

export GREP_OPTIONS='--color=auto'

sets the environment variable that contains options to pass automatically to grep. Colors are useful for discovering in which point of a line a match is occurred.


find is used instead for searching files instead of text.

find -name pattern path

will find all files in path which names correspond to pattern. An example pattern can be *.txt. The command is recursive.

find can also execute a command on each item found:

find . -type d -exec rmdir {} \;

will delete each directory (-type d) found by passing it to rmdir. {} is a placeholder for the elements.

A combination of find and grep, or other commands, is often very handy for by passing IDEs and analyze your code from the command line:

grep -r 'function(' `find -name *.c directory`

will find every line in *.c files where you call function().

history | grep 'git commit'

will tell you all the commits made from this shell.

history | grep 'git commit' | tail -n 3

instead will show you the last 3 commit commands. Git will give you a better log of events of course, but this approach is applicable to any command, from cat to ssh.


I wanted to include also a bit of awk, but this article is getting long.

Just remember the power of plain text (as Pragmatic programmers say) and that Unix can be your IDE (this is from Matthew Weier O'Phinney). And that a look at the man page for the right command can save you a lot of work.


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}