O HSTR parecia atraente, mas acabou sendo pesado demais para o meu gosto.
Em vez disso, escrevi minha própria função bash:
# Removes the last command from the history that matches the given search
# string and re-executes it using the given replacement string.
#
# Usage:
# historysub SEARCH [REPLACEMENT]
# historysub -d SEARCH
#
# REPLACEMENT may be omitted to remove SEARCH from the executed command.
#
# -d removes the last command matching SEARCH from the history without
# executing a new command.
historysub()
{
local delete=0
local usage=0
local OPTIND=1
while getopts ":hd" option; do
case "${option}" in
d) delete=1 ;;
h) usage=1 ;;
?) usage=2 ;;
esac
done
shift $((OPTIND - 1))
local search="${1}"
local replacement="${2}"
usage_text=
usage_text+="Usage: ${FUNCNAME[0]} SEARCH [REPLACEMENT]\n"
usage_text+=" ${FUNCNAME[0]} -d SEARCH\n"
if (( usage )); then
echo -e "${usage_text}"
return $(( usage - 1 ))
fi
if [[ -z "${search}" ]]; then
echo -e "${usage_text}" >&2
return 1
fi
# Find the last matching history entry (excluding ourself).
local hist_info
hist_info=$(HISTTIMEFORMAT="" history | grep -F -- "${search}" | grep -vF -- "${FUNCNAME[0]}" | tail -n 1)
if [[ -z "${hist_info}" ]]; then
echo "${FUNCNAME[0]}: \"${search}\" not found." >&2
return 1
fi
local re='^[ \t]*([0-9]+)[ \t]+(.+)$'
local hist_num hist_cmd
hist_num=$(sed -E "s/${re}//" <<< "${hist_info}")
hist_cmd=$(sed -E "s/${re}//" <<< "${hist_info}")
history -d "${hist_num}"
if (( delete )); then
echo "Removed: ${hist_cmd}"
return 0
fi
local cmd="${hist_cmd/${search}/${replacement}}"
echo "${cmd}"
# Add the new command to the history.
history -s ${cmd}
${cmd}
}
Agora, posso executar historysub TYPO CORRECTION
para executar novamente um comando com uma correção. Não é tão bom quanto poder editar o comando antigo de forma interativa, mas acho que deve ser bom o suficiente para as minhas necessidades.