Adding a -p option to touch

I’ve sometimes wished that the UNIX touch command had the same -p option as mkdir. With a little bit of scripting, it can:

#!/bin/sh

mkdir="/bin/mkdir"
touch="/usr/bin/touch"

for arg in $*; do
    if [ "$arg" = "-p" ]; then
        opt_p=true
        continue
    fi
    if [ "$opt_p" = "true" ]; then
        $mkdir -p $(dirname $arg) && $touch $arg
    else
        $touch $arg
    fi
done

Su su sudo: oh no

The other day I wanted to enable IP forwarding on my Linux box (so that it could forward packets from a tun virtual interface being used by VTun to the physical interface connected to my home network).

I looked up it up and it turns out that it’s a simple setting in a file in the /proc filesystem, so I did what seemed obvious and logical at the time:

marca:~$ sudo echo "1" > /proc/sys/net/ipv4/ip_forward
-bash: /proc/sys/net/ipv4/ip_forward: Permission denied

I took this to mean that my kernel was not compiled with ip_forward support and then wasted a bunch of time building a new kernel.

Finally, it dawned on me. Duh. The echo command is a shell built-in so sudo has no effect.

I didn’t need a new kernel. All I had to do was:

marc:~$ sudo bash
root:~# sudo echo "1" > /proc/sys/net/ipv4/ip_forward 
root:~# cat /proc/sys/net/ipv4/ip_forward
1

or even:

marc:~$ sudo sh -c 'echo "1" > /proc/sys/net/ipv4/ip_forward'

Sigh.

I thought of the idea of preventing this in the future by defining a bash function that detects builtins:

function sudo()
{
    if [ $(type -t "$1") == "builtin" ]; then
        echo "sudo bash function: ERROR - \"$1\" is a shell builtin" 1>&2
        return 1
    fi

    command sudo "$@"
}

which works for some cases but unfortunately doesn’t help for the case above, because the redirection permissions are checked before the function is executed. Sigh.

Blast from the past: Sniglets

I’m reminded today of Sniglets. I grew up in the 1980s watching lots of HBO, so Rich Hall’s little segments from Not Necessarily the News occupy a special place in some dark corner of my cerebrum. I can still remember to this day:

  • flen – the yucky stuff that accumulates under the cap of a ketchup bottle.
  • accello-yellow – someone who speeds up when they see a yellow traffic light

I just thought of a sniglet of my own. It’s a term for when you spend a couple of hours writing fancy little bash functions that do really specialized things that are fun but perhaps of questionable use.

I call this: “bashturbation”.

Having a bash with bash

Let’s say we want to write a command that allows you to take the output of the previous command and stick it in your editor so you can page through it, save it, email it, etc.

One way to do it is with bash’s “process substitution” feature. Try this:

$ ls -l
$ cat <($(tail -1 $HISTFILE)) | vim -

One problem with this is it won’t work if you change “vim” to “emacs”, because Emacs doesn’t like to read stdin. I tried all kinds of stuff including “emacs -nw -t /dev/tty /dev/stdin” and such.

Well, here’s an even more general solution:

with-temp-file ()
{
    local _prefix=$1; shift
    local _tmpfile_var=$1 ; shift
    local ${_tmpfile_var}=$(mktemp -t ${_prefix})
    eval local _tmpfile_value=\${$_tmpfile_var}
    eval "$@"
    rm ${_tmpfile_value}
}

edlo ()
{
    with-temp-file "edlo" tmpfile \
        '$(tail -1 $HISTFILE) > $tmpfile && $EDITOR $tmpfile'
}

Actually for bash versions 2 and up, it turns out we can clean this up a tad using the new syntax for indirect references to variables:

--- edlo.sh.2006-04-29-152010   Sat Apr 29 15:19:53 2006
+++ edlo.sh     Sat Apr 29 15:25:11 2006
@@ -3,7 +3,7 @@
     local _prefix=$1; shift
     local _tmpfile_var=$1 ; shift
     local ${_tmpfile_var}=$(mktemp -t ${_prefix})
-    eval local _tmpfile_value=\${$_tmpfile_var}
+    local _tmpfile_value=${!_tmpfile_var}
     eval "$@"
     rm ${_tmpfile_value}
 }

This should work in any editor, including X11 editors since we’re not using stdin. And the with-temp-file function is a general utility function that could be used for other stuff. Here’s another function that uses it:

eoo () 
{ 
    local _cmd="$@";
    with-temp-file "eoo" tmpfile '$_cmd > $tmpfile && $EDITOR $tmpfile'
}

This one is when you already know that you want to capture the output of a particular command – e.g.:

$ eoo ls -l
$ eoo finger

Enjoy.

Unix Power Tools, Third Edition

Stupid bash trick of the day

function _globdo
{
    local arg="$1"
    local dir=$(dirname $arg)
    local base=$(basename $arg)
    shift
    find $dir -name $base -exec "$@" {} \;
    set +f
}

alias globdo='set -f; _globdo'

The function/alias combo is get around automatic globbing and make it possible to specify glob patterns without having to quote them. See Simon Tathams’s Magic Aliases article for more info.

Examples of usage:

globdo *.c grep -H union
globdo /some/tree sed -i .bak 's/foo/bar/g'

Some tools like GNU grep already have recursive capabilities, but what I like about this approach is that it basically gives you recursive capabilities for all your tools and it does it in a consistent manner. To me it’s nicely in line with the Unix philosophy of having small tools that do particular tasks well and then stringing them together to create more complex behavior.

I hope that you find it useful. Comment if you have any improvements…