Issue
When using tools like grep
or some git
output (for status
, for example), I often want to make something with the (last) file returned in the list, like copying it to the clipboard or viewing it.
I'd like to automate that with a script that would rerun the last command, and identify the last returned file name, with such as script:
#!/usr/bin/env bash
# Retrieve the last command from the shell history.
last_command=$(history | tail -n 1)
# Check if the last command is empty.
if [ -z "$last_command" ]; then
printf >&2 "No command found in the shell history.\n"
exit 2
fi
# Run the last command and capture its output.
command_output=$($last_command)
# Extract the last line (assuming it's a list of files).
last_file=$(printf "%s" "$command_output" | tail -n 1)
# Debugging information.
printf "Last file: %s\n" "$last_file"
Though, for whatever reason which escapes me, history
does return the last command when run interactively from the command line, but it does not when run from the script. Hence last_command
is always empty...
With set -x
:
++ history
++ tail -n 1
+ last_command=
+ [[ -z '' ]]
+ printf 'No command found in the shell history.\n'
No command found in the shell history.
+ exit 2
Any idea?
(PS- I've also tried many different alternatives, such as using fc
, but with no more success.)
EDIT -- Changing the first command to:
history_file="$HOME/.bash_history"
last_command=$(tail -n 1 "$history_file")
shows me another last command than the real last command outputted by history
!??
Solution
Like the man page indicates, you have to set -o history
to make history available to scripts; but even then, the feature is enabled independently from your current interactive history. Since this seems like it's intended entirely for interactive use, it's probably something you should make into a function in your .bash_profile
or similar instead.
rerun () {
local last_command=$(history 2 | sed -n 's/^ *[1-9][0-9]* *//p;q')
# Check if the last command is empty.
if [ -z "$last_command" ]; then
echo "rerun: No command found in the shell history" >&2
return 2
fi
$last_command | tail -n 1
}
This is still way too simplistic if the last command was a pipeline. You want to eval
the last command to really repeat it.
(I find this too limited to be of actual use. Just press the up arrow and add | tail -n1 | xargs cp -t dest
to copy the last file in particular someplace. More often, I want to copy or otherwise manipulate all the files or lines.)
Answered By - tripleee Answer Checked By - Senaida (WPSolving Volunteer)