I am enjoying reading Mr. Neighborly’s Humble Little Ruby Book by Jeremy McAnnally. It’s a very easy read. I just finished chapter 3, and even though I’ll likely read the whole thing in the free PDF, I’ve ordered the print version to support this wonderful author and also I expect it will make a handy reference.

Along with the naturally dry instruction on the ins an outs of a programming language which he explains quite well, he includes humourous sample code and makes little language quirks delightfully easy to remember, such as:

For example, if you were creating a roleplaying game and wanted to set the possible ranges for the height of each race (in inches), you could type:

human = 48..81
elf = 40…68
grotesquely_huge_guy = 120..132

Ranges can use either two dots, which indicates an inclusive range of all values including the beginning value and the end value, or three dots, which excludes the last value. This seems backwards at first glance, but in truth that third dot is so fat that it pushes the last element out of the range. I am not kidding; crack open a debugger and find out for yourself.

I wanted to take the output of a command and put it in a temporary variable so I can append a string to it. (Trying to script perforce to append something to my client spec without interactive involvement.)

First attempt:
$ p4 client -o > $CLIENTSPEC
c:cygwinbinbash: $CLIENTSPEC: ambiguous redirect
I later learned that redirect is only for files.

Next attempt:
$ TEST=`p4 client -o`
$ echo $TEST
//depot/apps/diamond-calendar-preview/… //sallen-LENOVO/svn/openlaszlo/branches/pagan-deities/diamond-calen //depot/apps/diamond-amaranth-ms2/… //sallen-LENOVO/svn/openlaszlo/branches/pagan-deities/diamond-amaranth- //depot/sandbox/my-webtops/… //sallen-LENOVO/svn/openlaszlo/branches/wafflecone/diamond/client/my-webtops/. ..
which seems to have swallowed line endings and only provided the last few lines of output.

My colleagues at Laszlo, Trebor Fenstermaker and Chris Pettitt and ptw, showed me the error of my ways and provided some good tips. Trebor noted that there is a length limit for shell variables and that line endings will get lost. Chris introduced a combination of pipe and awk -v which did the trick. At first I thought Tucker’s simple echo solution wasn’t working, but he pointed out that I just needed to properly parenthesize my commands.

What worked:
p4 client -o | awk -v append=” //depot/apps/test/… //sallen-test/svn/openlaszlo/branches/pagan-deities/test/…” ‘{ print $0 } END { print append }’ | p4 client -i

Even simpler:
(p4 client -o; echo ” //depot/apps/test/… //sallen-test/svn/openlaszlo/branches/pagan-deities/test/…” ) | p4 client -i

Notes:

  • Redirect only works for files, there are lots of different types of redirects (> is a simple redirect of stdout to a file, >> will append to a file, 2> will redirect stderr)
  • awk -v will define a variable which can then be used in the awk script
  • You need to properly parenthesize your commands:

    ( p4 client -o; echo “Thing to append” ) | p4 client -i

    The parens will execute the p4 and echo commands in a sub-shell so the output of both will be piped to the next. Without the parens you have said:

    p4 client -o; ( echo “Thing to append” | p4 client -i )

    I.e., run the client command, then run echo to a pipe.

  • Pipe will let you take the stdout of one command and send it to the stdin of another:

For some reason, since I set up my new machine, when I p4 sync I would get directories that aren’t writeable. This means that lzx files won’t compile since the swf needs to be written into the directory.

To work-around this, I tried to just set permissions on all the directories. My first attempt (below), didn’t work…. anyone know why? the second one is more verbose and did work.

$ find * -type d | chmod a+w
chmod: missing operand after `a+w’
Try `chmod –help’ for more information.

Verbose work-around:
$ for i in * ; do if [ -d $i ]; then chmod a+w $i ; fi ; done

A better answer: the chmod command does not accept arguments on stdin, so you can’t just pipe a file list to it:

$ find . -type d -print0 | xargs -0 chmod a+w

xargs is your friend