Procrastiblog

January 6, 2007

The Unix Shell: Argh

Filed under: Tech — Chris @ 6:26 pm

Suppose you’re trying to write a simple shell script. And suppose you very badly want to put a command into a shell variable before you execute it. And suppose that command very badly needs to accept double-quoted strings as arguments. Oh, the layers of indirection! How will the shell tokenize such a thing?

Let the command in question be the following homely shell script.

string-arg.sh:  #! /bin/sh  # Usage: string-arg.sh [-s STRING]*  while test ${1+set}; do    case $1 in      "-s")         if ! test ${2+set}; then          echo "no string after -s"          exit 1        else          echo "string arg=\"$2\""           shift 2          continue        fi    esac    echo "bad arg: $1"     exit 1  done

Let’s see what happens.

% ./string-arg.sh -s "quoted arg"string arg="quoted arg"% cmd="./string-arg.sh -s \"quoted arg\""% echo $cmd./string-arg.sh -s "quoted arg"% $cmdstring arg=""quoted"bad arg: arg"% eval $cmdstring arg="quoted arg"

AND REMEMBER, KIDS: echo `foo` gives you the output of foo and { foo; echo $? } gives you its exit value.

if foo then bar fi

executes bar if foo succeeds (conventionally), which is equivalent to

foo && bar

in the short-circuiting parlance.

if ! foo then bar fi

executes bar if foo fails (conventionally), which is equivalent to

foo || bar

in the short-circuiting parlance.

if `foo`then bar fi

executes bar if the command output by foo exists and returns exit value 0 (if it doesn’t exist, it will just exit).

if test `foo`then bar fi

executes bar if foo doesn’t produce any output.

[UPDATE] One more thing. Setting shell variables.

% CMD=cmd argbash: arg: command not found% CMD= cmd argbash: cmd: command not found% CMD= "cmd arg"bash: cmd arg: command not found% CMD="cmd arg"% echo $CMDcmd arg

This often trips me up, because make is much more forgiving and I hack more Makefiles than shell scripts.

[UPDATE 1/8/2007] I got the if-then stuff wrong the first time. Which goes to show you how desperately I need this tutorial. In shell-world exit code 0 is “true” and exit code not-0 is “false”. This is sort of the opposite of the C convention, with the caveat that exit values and arithmetic values shouldn’t be conflated.

Another trip-up from C to the shell is that whitespace makes a bigger difference. if ! foo; then bar; fi is not the same as if !foo; then bar; fi.

if foothen barfi

is not the same as if foo then bar fi. {foo; bar;} is not the same as { foo; bar;}. And so on, world without end.

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.