Keeping Your SSH Sessions Alive Through NAT Firewalls

I found this article Keeping Your SSH Sessions Alive Through Pesky NAT Firewalls which explained how to keep SSH connections alive through NAT firewalls. I’m behind a NAT router and my SSH connections are always timing out due to inactivity, and it annoys the shit out of me. I’ve been putting up with it for ages, and tonight I finally got around to searching for a solution. The solution is to edit your ~/.ssh/config file and add:

Host *
    ServerAliveInterval 240

That will make the server send a keep-alive packet every four minutes, which out to do it. Haven’t tried it yet, but expect it will work. Will configure my systems now…

Update: that didn’t seem to work for me. :(

Maybe this is a client setting?

Anyway, I did some more research, and I found that PuTTY has a configuration option in the Connection settings “Sending of null packets to keep session active”, “Seconds between keepalives” which defaults to 0 (turned off). So I’m gonna try with that now.

Setting a default value if a bash variable is undefined

Say you want to take an optional command line argument to your script. That means that maybe $1 is set to a value, or maybe it’s not. You can read out the value and assign a default in the case that $1 is not set using the syntax:

  variable=${1:-default-value}

Which will set $variable to “default-value” if $1 is not set.

Replacing new lines with nulls in bash

If you have a list of file names separated by new lines, and you want to turn it into a list of file names separated by null characters, for instance for use as input to xargs, then you can use the tr command, like this:

  $ cat /path/to/new-lines | tr '\n' '\0' > /path/to/null-separated

I found a whole article on various ways to replace text on *nix: rmnl — remove new line characters with tr, awk, perl, sed or c/c++.

Extracting a single file from a tar archive

You can use a parameter to the -x command line switch to tell the tar command that you just want to extract one particular file from the archive. For example:

  $ tar -x filename/to/extract -f tarfile.tar

You can use the -O command line switch in conjunction with the above to have the file’s contents printed on stdout rather than created in the file system.

Changing parent’s directory from a subshell

I was trying to figure out how to have a child process change the current directory of a parent process. Turns out you can’t quite do that. One thing I guess you could do is export a global variable and then have the parent check that when the child returns, but I decided on another approach. What I do is write a file to ~/bin/errdir that contains a single line in the format:

  pushd "/path/to/directory"

I can then source this as a command file after my script has run to change directory into the directory where the last erroneous file was encountered with the command:

  $ . errdir

When I’m finished I can just type ‘popd’ to return myself to wherever I was before I changed into the error directory.

Error handling in bash

I’ve been learning about approaches to error handling in bash. I found Error handling in BASH, Exit Shell Script Based on Process Exit Code, Writing Robust Bash Shell Scripts and Bash: Error handling all of which contained a nugget of useful information.

Particularly I learned about $LINENO, set -e (equiv: set -o errexit), set -o pipefail, set -E, set -u (equiv: set -o nounset), set -C (equiv: set -o noclobber), #!/bin/bash -eEu, trap, shopt -s expand_aliases, alias, $PIPESTATUS, subshells, unset, and more.

If you call exit without specifying a return code then $? is used, I didn’t know that.

I found this code snippet that demos a relatively race-condition free method of acquiring a lock file:

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; 
then
   trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

   critical-section
   
   rm -f "$lockfile"
   trap - INT TERM EXIT
else
   echo "Failed to acquire lockfile: $lockfile." 
   echo "Held by $(cat $lockfile)"
fi