You are currently browsing the monthly archive for September 2007.

This took much longer for me to nail than I care to admit. How to test if a bash script argument is an integer?

test "$1" -ge 0 -o "$1" -lt 0 2>&- && echo "$1" is an integer

This tests if the value of $1 is greater-than-or-equal-to 0 or is less-than 0. The 2>&- closes test‘s stdout (you could also use 2>/dev/null). Squashing stderr is necessary to mask the “integer expression expected” error that occurs when $1 is not an integer.

Or if you prefer the ‘[‘ syntax:

[ "$1" -ge 0 -o "$1" -lt 0 2>&- ] 2>&- && echo "$1" is an integer

Remember ‘[‘ is actually a command – hence the required space following it – so it also has a stderr that can be closed or redirected.

This is a belated posting about dealings I had back in March with the slowness of Net::SFTP even with Math::BigInt::GMP installed. In short, I successfully replaced Net::SFTP with Net::SFTP::Foreign in my scripts and am now enjoying native transfer rates.

Foreign uses the system’s ssh clients instead of a pure pure implementation
as Net::SFTP does. With Net::SFTP::Foreign I reduced a 1.2GB download from 4 hours to 20 minutes.

It also doesn’t have the 1GB ssh rekeying hang that an unpatched Net::SFTP has.

There is a Compat sub-module that allows Net::SFTP::Foreign to work as a drop in replacement to Net::SFTP. In version 0.90_15 I had to comment out line 85 of, dontsave => !defined($remote), to get it to work. I didn’t report this to the maintainer at the time (sorry). I now see that there have been over a dozen releases of Net:SFTP::Foreign since I investigated this and I don’t know if this modification is still necessary.

I recommend Net::SFTP::Foreign where speed is important and a native client is available. But before rushing out to adopt it, do know that it prefers SSH key authentication. It won’t take passwords without some hoop jumping as described in the perldoc.

Perl’s FindBin is handy when a script needs to know its home. What is the bash equivalent of Perl FindBin? Here are some options.

Bin="$( readlink -f -- "$( dirname -- "$0" )" )"
echo $Bin

To avoid the dirname fork, you can replace it with a variable manipulation.

Bin="$( readlink -f -- "${0%/*}" )"

The ‘%’ operator deletes the shortest possible match from the right, so will remove the file name and terminal ‘/’ from the $0 (the command executing).

Finally, there’s the “go there and see for yourself” approach.

Bin="$(cd -- "$(dirname "$0")" && pwd)"

In all cases I’m trying to be careful to quote the variables and expressions to allow for spaces in path names. Also, I’m adding -- after commands as a signal to stop scanning for options. Otherwise, if a pathname beginning with a - would be interpreted as an option.


September 2007