The other day, while working on setting up a new virtual machine for testing purposes, I ran the following command to get my networking configured "ifconfig enp0s8" down only to be greeted with the following:
GAH! Why do I need root privileges to bring up or down an interface? Why do I need to be root in order to use dhclient to get assigned an IP address via DHCP? Sigh. Well it's no big issue, I just ran sudo !! to run the last command but this time as root. Ok, that was easy enough. To be honest, accidentally running a command without sudo happens more often than I'd like to admit. To make life easier, and to save a few keystrokes in the long run, it can pay dividends to make an alias that will do the equivalent of sudo !!
Command Breakdown
alias gah='sudo $(history -p \!\!)'
1. alias - Bash feature that allows us to map a string to a simple command
2. gah - The name of the alias that we are creating
3. ='COMMAND' - What to do when we run gah on the command line. Command defined between single quotes
4. sudo - Command that will allows us to execute the following command as a different user
5. $(history -p \!\!) - Bash evaluated expression that will print out the last command that was run and all supplied arguments.
Now when I try to bring the interface back up and forget to use sudo I can just type "gah" in frustration:
To make this more permanent I added it to the ".bashrc" file in my home directory "(~/.bashrc) so that it will be available whenever I pull up a terminal.
One useful alias down? maybe I should finally get around to adding one for gerp='grep'?
While we're talking productivity, along the same track as the "! !" operator in bash (repeat the previous command) is: bash_history.
The history command lists previous commands, executed commands by number, and can be referenced by running "! #" to rerun any previous command. This can be extremely useful when scripting in shorthand. For instance, I recently put together an auto upload unpacker script for a webpack and nodejs website we were building. The resulting command was:
rm -rf site.bak/*;cp ndist.tar.gz dist.tar.gz; mv * site.bak/;mv site.bak/wordpress/ ./;cp site.bak/dist.tar.gz ./;tar -xvf dist.tar.gz ;mv dist/* ./;mv site.bak/unpack.sh ./;chmod -R 555 /var/www/site.com/; chmod -R 700 /var/www/site.com/wordpress/;chown -R www-data /var/www/site.com/;rm -rf dist/; rm -rf ndist.tar.gz
But I'd already run each of these commands individually and was looking to compile them into a single bash script. To accomplish that with history I ran this:
echo "rm -rf site.bak/*;!1804; !1805;!1806;!1807;!1756; !1757;!1808;!1809;!1810;!1811;!1812" > unpack.sh && chmod +x unpack.sh
Now all I have to do to unpack a new build of the site is run:
./unpack.sh
Another great feature of history is its text matching. For instance, I frequently log into my blog's VPS to tinker. Rather than type out the full ssh command I can execute "!ssh". This will run the most recent command in my bash_history beginning with ssh.
In the above case this could be shortened further to "!ss" or even "!s" presuming that the most recent history entry starting with the letter "s" is the desired command. Endless productivity through bash!
Matthew Toussain
https://twitter.com/0sm0s1z