Entering a Null Byte Interactively

A nice little fact you learn along the way when you’re always in the terminal is that the characters that appear when you press control-C, namely ^C, carry more meaning than one might think initially. The caret (^) can be thought of the value 0b100000 (that’s 127 in decimal) XOR’ed with the ASCII value of C. In this case, it would yield ASCII 3, which is exactly what programs that run in raw mode (like vim) would receive. If you take a look at the ASCII man page (man 7 ascii), you’ll see printable characters on the right column. You can apply the same logic to many of them, i.e. ^@, ^A, …, ^Z. There’s an exception, ^?, which stands for backspace. That’s right, you can press control-? (control-shift-/ on a qwerty keyboard) in a “normal” terminal and it should do exactly the same as pressing backspace. On my system, even control-8 works, but I digress.

[Read more]

-eq is slightly faster than =

Bash (5.2.15):

$ bench () { timeout 60 env -i bash -c "trap 'echo \$i; exit' TERM; i=0; while [ 0 $1 0 ]; do i=\$((i+1)); done"; }; python3 -c "print(round((1 - $(bench "-eq")/$(bench "=")) * 100, 2), '%')"
7.58 % # 5.76 % or 4.68 % or 3.65 %, YMMV

Dash (0.5.12):

$ bench () { timeout 60 env -i dash -c "trap 'echo \$i; exit' TERM; i=0; while [ 0 $1 0 ]; do i=\$((i+1)); done"; }; python3 -c "print(round((1 - $(bench "-eq")/$(bench "=")) * 100, 2), '%')"
13.07 %
[Read more]

The best Termux SSH setup

I’m a huge lover of KeePass (NOT KeePassXC), it’s by far the most advanced password manager (I mean, what password manager supports case-sensitive, regular expression XPath-selector search and replace operations on its internal XML tree? It’s a feature that I’ve used extensively to manage my hundreds of passwords with custom fields; but I digress already…). KeePass has this one particular feature that, if missing in any other password manager, is an immediate deal-breaker for me: SSH Agent Integration. It’s such a good feature for many reason, but I will elaborate on that in another article.

[Read more]

Preexec hooks are finally trivial in bash 5.3

When ricing their prompts, bash powerusers often face a difficult problem: It is not trivial to run something before the execution of a command and also have it run in the current shell. Commonly, you would want to do such a thing to automatically measure the time it took for your command to run. The most well-known solution is to use bash-preexec, which uses bash’s built-in DEBUG trap. However, it’s a bit convoluted for the task it’s trying to achieve, since the DEBUG trap is not only triggered before your command runs, but before any simple command, for command, case command, select command, every arithmetic for command, and before the first command executes in a shell function, and it will also be active inside your PROMPT_COMMAND (not in prompt expansion tho). Therefore, it has to be very careful in it’s implementation. And of course, you cannot use the DEBUG trap for your own sake when you use this.

Since the release of bash 5.3 however, there’s finally a new, easy way to achieve this:

1PS0='${ __cmd_start=$BASH_MONOSECONDS;}'
2PS1="[ \$((BASH_MONOSECONDS - __cmd_start))s ] \u@\h:\w\$ "
[Read more]

Implementing cat in pure bash

Implementing a function in bash that simply echos its standard input to standard output is surprisingly difficult. Here’s one possible golfed implementation:

bashcat(){ local z=\\0;while [ $z ];do LC_ALL=C IFS= read -rd '' l||z=;printf "%s$z" "$l";done;}

Cleaned up, it could look like this:

1bashcat () {
2    local trailing_nul='\0'
3    while [ $trailing_nul ]; do
4        LC_ALL=C IFS= read -rd '' chunk || trailing_nul=
5        printf "%s$trailing_nul" "$chunk"
6    done
7}
[Read more]