3

I have very basic linux skills and now am trying to parse some shell scripts. I see this line in one of the scripts:

if [ -n "$(which voltdb 2> /dev/null)" ];

I know that /dev/null is the bit bucket and that which prints out the path that would have been executed had I run voltdb at the command line. Also, the whole line is obviously an if statement. But I am confused about many other things here.

  1. Why is 2 being compared to /dev/null? These seem like incompatible types.
  2. What does the switch -n do? I am used to using switches like rm -r filename but the -n does not seem to pair with any command
  3. What do the brackets do? They seem to mean something else here than in this expression What is the meaning of this test expression []?

Basically, what does this line do? There are too many unknowns in this for me -- so it's a little bit like hearing a sentence in a foreign language and missing so many words that you can't catch the basic structure.

bernie2436
  • 6,655

2 Answers2

4

There's a lot going on in that fragment of code. Working from inside out:

which voltdb 2> /dev/null - The command executed here is which. which as invoked, will look a all entries in the PATH environment variable to find a command named "voltdb". If it finds an executable file named "voltdb" in one of the directories named in PATH, it will print the full-qualified name of the voltdb executable file.

To answer your #1, the "2>" is an example of redirection. Every Unix/Linux/*BSD process has 3 standard inputs and outputs, 0 is stdin, 1 is stdout, 2 is stderr. Programs meant to run on the command line typically print error messages to stderr. So, "2> /dev/null" is not numerically comparing 2 to "/dev/null", it's sending any which error output to /dev/null, a special file that just eats any input, and gives back 0 bytes of output.

Outside of that the $(...) construct means "run the enclosed command and lexically substitute any output right here, between '$(' and ')'". That's output substitution, something that shell programs do.

Outside the output substitution, the fragment does if [ -n "something" ];, where "something" is what which would have printed. The "if" is a shell flow-of-control construct, causing a block of code to execute when the pipeline of commands after the "if" exits with a "success" status.

The [ is actually an executable, that looks at command line arguments up to the ]. The "-n" flag usually means "true on non-zero-string-length next argument". That's the answer to your #2 and #3 questions. The [ ... ] construct gives true (exit with success code) or false (exit with failure code) answers to some logical conditions, in this case "non-zero string length".

Ultimately, that fragment would execute the "true" clause of an if-then-fi or if-then-else-fi flow of control when that shell's PATH has a directory with a voltdb executable file in it.

  • The facility 1>, 2>, etc. are called streams: http://en.wikipedia.org/wiki/Standard_streams – slm Oct 10 '13 at 19:30
  • 1
    @slm Streams is a more recent concept (recent as in System 5, so recent is relative). What it really is is the file descriptors of STDIN, STDOUT, and STDERR. Since those are always opened in that order for every process, and numbering starts at 0, those are always numbered the same. – kurtm Oct 10 '13 at 20:07
  • 1
    [ is actually the program test. On OpenBSD, the two are actual hard linked. On an Ubuntu 12.04LTS server, the two are distinct, although I'm not sure why. – kurtm Oct 10 '13 at 20:09
  • Not sure if they've always been accessible but you can access the file descriptors as 0,1,2 and also /dev/stderr, /dev/stdin, and /dev/stdout, at least in Linux. – slm Oct 10 '13 at 20:10
2

That code is doing the following:

if [ -n "...." ];

The if statement is true if the results of the code when executed in the double quotes is empty.

The code in the double quotes:

$(which voltdb 2> /dev/null)

Runs the which voltdb command and redirects any output from this command that occurs on STDERR (standard error) to /dev/null. Basically we're not interested in it, so we're ignoring it.

The results of which voltdb will return the path to any executable on your PATH that matches the string voltdb.

Example

$ which time
/usr/bin/time

$ which time 2> /dev/null
/usr/bin/time

What about the 2> ?

2> is a shorthand notation for redirecting the output of one of the streams that is automatically setup for a program when it runs. The streams are as follows:

  • 0 - standard in (aka STDIN)
  • 1 - standard out (aka STDOUT)
  • 2 - standard error (aka STDERR)

So if you want to take the output of STDERR and get rid of it:

$ which time 2> /dev/null

If you want to take the output from STDOUT and re-direct it to STDERR:

slm
  • 369,824
  • what is the meaning of the 2> ? I see that you can redirect input and output with < and > but what does the 2 do? – bernie2436 Oct 10 '13 at 19:15
  • http://www.tldp.org/LDP/abs/html/io-redirection.html – Vombat Oct 10 '13 at 19:18
  • 1
    @akh2103 > redirects STDOUT, which is stream 1, so 1> is the same as >. Putting a number in front of either > or < gives the file descriptor you want to redirect instead of the default. – kurtm Oct 10 '13 at 20:11