Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get last command run without using `!!`?

Tags:

shell

zsh

zshrc

I'm trying to alias _! to sudo the last command, but I'm running into roadblocks. !! doesn't seem to work in my .zshrc file, and sed has given me repeated problems. I tried using the following command, and several variations of it, but to no avail.

history | tail -1 | sed -e 's/[^0-9\*\ ]+/\0/g'

However, this still interpreted the piped input as a file, instead of a string of text. I also tried a variation using awk:

history | tail -1 | awk '{ gsub("/[^0-9\*\ ]+", "") ; system( "echo" $1 ) }'

I'm sure I'm just having some trouble putting the commands in correctly, but some help would be appreciated.

like image 396
Brandon Anzaldi Avatar asked Dec 14 '22 17:12

Brandon Anzaldi


1 Answers

You can use the fc built-in to access the history programmatically. For example, I believe this will behave as you wish:

alias _!='fc -e "sed -i -e \"s/^/sudo /\""'

With no arguments, fc (short for "fix command") fires up $EDITOR on your previous command and runs the result of your editing. You can specify a different editor with the -e option; here, I'm specifying a non-interactive one in the form of a sed command that will insert sudo in front of the command line.

The command assumes GNU sed. As written, it will also work with the version that ships on modern BSD/macOS, but by way of a hackcident: it treats the -e as an argument to -i instead of a new option. Since the -e is optional with only one expression, this works fine, but it means that sed makes a backup of the temp file with -e on the end, which will hang around after the command completes. You can make that cleaner by using this alternative version on those systems:

alias _!='fc -e "sed -i \"\" -e \"s/^/sudo /\""'

(That won't work with GNU sed, which sees the empty string argument as a filename to operate on...)

On older systems, a more portable solution could use ed:

alias _!="fc -e 'ed -s <<<$'\''s/^/sudo /\nw\nq'\'"

You can often get away with something simpler, like sudo $(fc -ln -1) (-l = list commands, -n = without numbers, -1 = only the last command), but in general you will run into quoting issues, since the command is output by fc the way it was typed:

% touch '/etc/foo bar'
touch: /etc/foo bar: Permission denied
% sudo $(fc -ln -1)
touch: '/etc/foo: No such file or directory

None of the above is limited to zsh, btw; fc dates to the original version of ksh, so it will also work in bash, etc.

like image 142
Mark Reed Avatar answered Jan 03 '23 19:01

Mark Reed