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}