Skip to content
Light Dark
Shell tidbits

Shell tidbits

(Updated: ) - 4 mins

Updated March 2026: Verified all examples still work on current Bash 5.x and Zsh. These POSIX-compatible tricks remain relevant — especially on minimal systems where fancy tools aren’t available.

Summary:

This is the first of a long (maybe) series of blog posts with some less known shell features. Unless otherwise specified, bash is the shell of reference.

Index

Poorman encryption

Calling this encryption is a bit unpolite, but let’s do it, we don’t care right?

From wikipedia:

ROT13 ("rotate by 13 places", sometimes hyphenated ROT-13) is a simple letter substitution cipher
that replaces a letter with the 13th letter after it, in the alphabet.

I use this, sometimes, just to make things a bit arcane for those n00bs not looking enough far, and to pass sensible, obfuscated data from one script to another.

To ROT13 a string we can use tr (translate or delete characters), so I wrote a simple function that take a string as input and output its ROT13 permutation.

rot13 () {
        [[ $# -eq 0 ]] && return
        tr a-zA-Z n-za-mN-ZA-M
}	# ----------  end of function rot13  ----------

For example, let’s ROT13 and back an “Hello World”

[tmow@Ade ~]$ echo "$(rot13 "Hello World")"
Uryyb Jbeyq
[tmow@Ade ~]$ echo "$(rot13 "Uryyb Jbeyq")"
Hello World
[tmow@Ade ~]$

Don’t use this to store passwords as it’s not safe at all (exept against idiots).

Redefine a command

What if you need to execute a script on different unixes with different implementations of, let’s say, awk and sed?

Aliases cannot be easily used inside a script, so often people set an AWK and SED variable and than use that varbiale inside the script, instead of calling directly the awk/sed variant.

I really don’t like “executing” variables and I don’t like to ignore shellcheck exceptions.

So, the most elegant way I’ve found is to redefine a command with a function.

case "$(uname -s)" in
    SunOS)
        awk () {
            # Add some code here to log somewhere that you are using nawk for
            # debugging purpose
            /usr/bin/nawk "$@"
        }
        # in bash we can export a function with -f
        export -f awk
        ;;
    *)
        ;;
esac

Functions are interepted before programs in the PATH environment variable, therefore if you are on SunOS, when you will call awk, bash will call the function awk and not the awk command.

Variable is defined

Since bash v4.2, we can test if a variable is set with

[[ -v VARNAME ]]

Before these days and on Unices where bash >4.2 it’s a dream, we can use typeset (or declare).

typeset -p VARNAME

I normally use this in a function that I use every time I need to test if a variable is defined.

varisdefined () {
	typeset -p ${1:-} >/dev/null 2>&1
} # varisdefined

That I can use this way:

if ! varisdefined foo; then
    # die is another funcion of mine, that I use to log and exit cleanly from a script.
    die "foo is not defined" 5
fi

Poorman basename

On some Posix unix, there is not yet basename, you can obtain the same result with just a printf and a the bash strings operations.

_mypath="/usr/bin/bash"
printf "%s\n" "${_mypath##*/}"

Poorman dirname

Same as basename…

_mypath="/usr/bin/bash"
printf "%s\n" "${_mypath%/*}"

Watch Out

A few things that bit me or others over the years:

  • export -f is Bash-only. The function export trick in the “Redefine a command” section won’t work in dash, ash, or strict POSIX shells. On systems where /bin/sh isn’t Bash (Debian, Ubuntu), scripts using #!/bin/sh won’t see exported functions.

  • [[ -v VARNAME ]] fails silently on old Bash. On Bash < 4.2, the -v test doesn’t exist. It won’t error: the condition just evaluates to false. Your script proceeds with the variable “undefined” even if it’s set. The typeset -p fallback is safer for portable code.

  • Empty strings in parameter expansion. The poorman basename ${_mypath##*/} returns an empty string if _mypath is empty. If you’re using the result in a rm or mv command, that’s a problem. Always check for empty input first.

  • ROT13 is not obfuscation. I know, I said it above. But people still use it to “hide” API keys in scripts. Don’t. Any base64 decoder can spot ROT13 by pattern. If you need real obfuscation in a script, use openssl enc or a proper secret manager.

Antenore Gatta

Antenore Gatta

A proud and busy Hacker, Father and Kyndrol

Useful Tricks?

If these shell tricks saved you from writing yet another one-liner from scratch, consider a small contribution.

Most readers scroll past. Less than 3% of readers contribute to keeping independent technical content free and accessible.

Post comment

Markdown is allowed, HTML is not. All comments are moderated.