Default grep options

When you’re searching a set of version-controlled files for a string with grep, particularly if it’s a recursive search, it can get very annoying to be presented with swathes of results from the internals of the hidden version control directories like .svn or .git, or include metadata you’re unlikely to have wanted in files like .gitmodules.

GNU grep uses an environment variable named GREP_OPTIONS to define a set of options that are always applied to every call to grep. This comes in handy when exported in your .bashrc file to set a “standard” grep environment for your interactive shell. Here’s an example of a definition of GREP_OPTIONS that excludes a lot of patterns which you’d very rarely if ever want to search with grep:

GREP_OPTIONS=
for pattern in .cvs .git .hg .svn; do
    GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=$pattern
done
export GREP_OPTIONS

Note that --exclude-dir is a relatively recent addition to the options for GNU grep, but it should only be missing on very legacy GNU/Linux machines by now. If you want to keep your .bashrc file compatible, you could apply a little extra hackery to make sure the option is available before you set it up to be used:

GREP_OPTIONS=
if grep --help | grep -- --exclude-dir &>/dev/null; then
    for pattern in .cvs .git .hg .svn; do
        GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=$pattern"
    done
fi
export GREP_OPTIONS

Similarly, you can ignore single files with --exclude. There’s also --exclude-from=FILE if your list of excluded patterns starts getting too long.

Other useful options available in GNU grep that you might wish to add to this environment variable include:

  • --color — On appropriate terminal types, highlight the pattern matches in output, among other color changes that make results more readable
  • -s — Suppresses error messages about files not existing or being unreadable; helps if you find this behaviour more annoying than useful.
  • -E, -F, or -P — Pick a favourite “mode” for grep; devotees of PCRE may find adding -P for grep‘s experimental PCRE support makes grep behave in a much more pleasing way, even though it’s described in the manual as being experimental and incomplete

If you don’t want to use GREP_OPTIONS, you could instead simply set up an alias:

alias grep='grep --exclude-dir=.git'

You may actually prefer this method as it’s essentially functionally equivalent, but if you do it this way, when you want to call grep without your standard set of options, you only have to prepend a backslash to its call:

$ \grep pattern file

Commenter Andy Pearce also points out that using this method can avoid some build problems where GREP_OPTIONS would interfere.

Of course, you could solve a lot of these problems simply by using ack … but that’s another post.

Restricting public keys

It may be the case that while you’re happy to allow a user or process to have public key authentication access to your server via the ~/.ssh/authorized_keys file, you don’t necessarily want to give them a full shell, or you may want to restrict them from doing things like SSH port forwarding or X11 forwarding.

One method that’s supposed to prevent users from accessing a shell is by defining their shell in /etc/passwd as /bin/false, which does indeed prevent them from logging in with the usual ssh or ssh command syntax. This isn’t a good approach because it still allows port forwarding and other SSH-enabled services.

If you want to restrict the use of logins with a public key, you can prepend option pairs to its line in the authorized_keys file. Some of the most useful options here include:

  • from="<hostname/ip>" — Prepending from="*.example.com" to the key line would only allow public-key authenticated login if the connection was coming from some host with a reverse DNS of example.com. You can also put IP addresses in here. This is particularly useful for setting up automated processes through keys with null passphrases.
  • command="<command>" — Means that once authenticated, the command specified is run, and the connection is closed. Again, this is useful in automated setups for running only a certain script on successful authentication, and nothing else.
  • no-agent-forwarding — Prevents the key user from forwarding authentication requests to an SSH agent on their client, using the -A or ForwardAgent option to ssh.
  • no-port-forwarding — Prevents the key user from forwarding ports using -L and -R.
  • no-X11-forwarding — Prevents the key user from forwarding X11 processes.
  • no-pty — Prevents the key user from being allocated a tty device at all.

So, for example, a public key that is only used to run a script called runscript on the server by the client runscript@client.example:

command="runscript",client="client.example",no-pty,no-agent-forwarding,no-port-forwarding ssh-rsa AAAAB2....19Q runscript@client.example

A public key for a user whom you were happy to allow to log in from anywhere with a full shell, but did not want to allow agent, port, or X11 forwarding:

no-agent-forwarding,no-port-forwarding,no-X11-forwarding ssh-rsa AAAAD3....19Q user@client.example

Use of these options goes a long way to making your public key authentication setup harder to exploit, and is very consistent with the principle of least privilege. To see a complete list of the options available, check out the man page for sshd.