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.
Replacing the current shell
-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 %
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.
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\$ "
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}