From the Canyon Edge -- :-Dustin
Showing posts with label Hacks. Show all posts
Showing posts with label Hacks. Show all posts

Thursday, August 26, 2010

Buy 1, get 8 Free! Or, a Useful Awk Hack...


But first, a couple of updates...
  1. If you appreciated my errno post, you might be happy to know that /usr/bin/errno is now provided by the ubuntu-dev-tools package in Maverick. This probably won't be the permanent home for the utility (currently in discussions with Joey Hess about putting it in moreutils, and the kernel team about putting it in linux-tools). But while we debate among ourselves about the permanent location of the bike shed, you -- our Ubuntu users -- are welcome to go about using the tool.
  2. And if you liked my bash alert post, you might also be happy to know that the alert alias is also in Maverick's skeleton .bashrc. This only affects new Maverick installs, and you'll have to install the libnotify-bin package, but still, it's a useful tool, and a good start. Several people have suggested UDS-Natty sessions on how to make the tool more universally useful, and it would be cool to see those move forward in the next cycle.
Okay, now for another fun set of tools!

All too often, I found myself typing something like this:
... | awk -F":" '{print $3}'
That's a lot of wasted characters, and it's easy to flub them up.

And so I generalized it, with this 2-line shell script in /home/kirkland/bin/1:
#!/bin/sh
[ -n "$1" ] && ifs="-F\"$1"\" || ifs=
eval awk $ifs "'{print \$$(basename $0)}'" /dev/stdin

And then I made symlinks to this one script, for numbers 2-9:
cd $HOME/bin
for i in $(seq 2 9); do
ln -s 1 $i
done

And now I can:
errno "" | 1
euca-describe-instances | 2
cat /etc/passwd | 7 :

I started out with just simple aliases for 1..9, but I found myself often needing to change the input field separator (IFS). In case you'd prefer the simple aliases, you can use these:
for i in $(seq 1 9); do
alias $i="awk '{print \$$i}'"
done

What do you think?
  • Would you like to see these as /usr/bin/1 ... /usr/bin/9 in Ubuntu Natty?
  • Do you have a more efficient implementation?

:-Dustin

p.s. My wife, Kim, took both of these pictures recently, on the side of the road in Michigan and New York, respectively. Pretty birds, hard to photograph! :-)

Monday, July 26, 2010

Cogito Errno Sum


Ah, POSIX error codes. When systems programming, do you ever find yourself with an unfamiliar error code, and then you're off Googling what the heck it actually means? Where's the command line utility to just do this for you, right where you're at, in a terminal? It's actually pretty easy, with a glorified grep...

Try this script, which I store in ~/bin/errno:

#!/bin/sh -e
headers="/usr/include/asm-generic/errno*.h"
code="$1"
if echo "$code" | grep -qs "[0-9]"; then
grep -hw "\W$code\W" $headers | sed 's/^#define\s*//'
else
grep -hi "$code" $headers | sed 's/^#define\s*//'
fi

Now, you can run:

errno 36
ENAMETOOLONG 36 /* File name too long */

Or:

errno EEXIST
EEXIST 17 /* File exists */

Is this useful to you? It has been really useful to me any time I'm doing system level programming or debugging.

I have long wanted to drop this little script in /usr/bin/errno, but I haven't found the right package to own something like this. Maybe a kernel package, since it uses the kernel headers? Opinions? Let me hear them!

:-Dustin

I think, an error number, I am :-)

Dear Bash, please ping me when you're done running $FOO


UPDATE: The "alert" alias has landed in Maverick's /etc/skel/.bashrc ... thanks for your support!!!

How often do you run a command line tool on your desktop that takes a really long time? Maybe something like make, debuild, rsync, or wget?

You probably kick off the long running job, and then alt-tab over to something more captivating than watching gcc fill your scroll back buffer -- maybe your web browser or news reader.

You occasionally pop back over to your shell to check on your job. Maybe it's still running. But maybe it finished a while ago. Dang.

No need to beat yourself up over wasted cycles. You can tell your shell to ping you when it's done. Just add this alias to your ~/.bashrc.


alias alert='notify-send --urgency=low -i "$([ $? = 0 ] \
&& echo terminal || echo error)" "$(history|tail -n1| \
sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

Install the notify-send utility, and source your new ~/.bashrc:

sudo apt-get install libnotify-bin
. ~/.bashrc

Now, run a long running job, and append "; alert" to the end of the command, like this:

sleep 20; alert

After running the target command, the alert alias will render a notify-osd pop-up on your desktop, telling you the command you just ran, and its exit code.


Nifty, huh?

:-Dustin

Friday, July 2, 2010

Keeping Pictures from Multiple Cameras in Temporal Order


I use as many as 4 different cameras, each serving a slightly different purpose.

In order decreasing order of portability, and increasing order of photo quality:
  1. Pocket -- a low-quality, but always present camera phone (either my Palm Pre or my G1)
  2. Small -- Canon Powershot SD1000
  3. Medium -- Kodak z812 IS
  4. Large -- Canon EOS Digital Rebel XTi
When I'm traveling, I might take 2 or more of these cameras, and shoot pictures all day long on different cameras. Sometimes, I'm shooting with one camera, and Kim is shooting with the other. At the end of the day, I want to merge all of these pictures, and look at them in order.

To keep this straight, I take great care to ensure that the embedded clocks in all of these cameras are perfectly in sync.

And when I'm processing my pictures, I often use gthumb to rename my pictures, embedding the timestamp in the name.


Other times, I'll write a small script to do this for me.

Earlier today, as I was stitching my pictures together from 3 different cameras, I realized that one of the clocks was off by about a day. I used this little script to fix the timestamps:

#!/usr/bin/php
<?php
$dh = opendir(".");
while (($file = readdir($dh)) !== false) {
if (preg_match("/^IMG_/", $file)) {
$s = stat($file);
touch($file, $s[9] - 86400);
}
}
?>
After I did that, I also needed to update the EXIF data embedded in the JPG too. To do that, I used jhead.

jhead -dsft IMG_*

Of course, running jhead on these files modified them yet again, so the file's timestamps are screwed up again. Let's cover our tracks.



#!/usr/bin/php
<?php
$dh = opendir(".");
while (($file = readdir($dh)) !== false) {
if (preg_match("/^IMG_/", $file)) {
$exif_data = exif_read_data($file);
touch($file, strtotime($exif_data['DateTime']));
}
}
?>


Enjoy!

:-Dustin

Printfriendly