5 Handy Bash Tricks in 2 Minutes

Jacob Herrington (he/him) on August 12, 2019

This article should only take you a couple of minutes to read, and you'll walk away with a handful of the bash tricks I constantly use. 1... [Read Full]
markdown guide
 

Nice list.

Please please please please please use double quotes around variables, unless you explicitly desire the shell to interpret the variable value. A simple example to illustrate the issue:

$ mkdir test_shell_behavior && cd $_
$ touch 'foo' 'xyz 123'
$ for file in * ; do cp $file $file.bak; done
cp: target '123.bak' is not a directory
$ ls
foo  foo.bak  xyz 123

$ rm foo.bak
$ for file in * ; do cp "$file" "$file".bak; done
$ ls
foo  foo.bak  xyz 123  xyz 123.bak

See this Q&A on unix.stackexchange and wooledge: Quotes for more details.


You can also use man -k instead of apropos


For testing shell globs, you can use echo

$ echo cp /some/path/to/file.txt{,.bak}
cp /some/path/to/file.txt /some/path/to/file.txt.bak
 

Cool! Thanks for the feedback, that is good advice. 🤠

 

I definitly recommand ${variable}, much better to look and feel more like you can't be wrong about it :)

 

To piggyback on the last one there, if you history:

$ history

the output should be a numerical list of commands you've entered in the past, like so:

10016  git status
10017  git commit
10018  git push origin master

If I wanted to run git status again (ie, repeat command 10016 from history), I could do something like this:

$ !10016

 
 

You could also pipe history too! Which could allow you to grep (and more) within your history:

$ history | grep "status"

10005  git status
10008  git status
10011  git status
10014  git status
10016  git status

:)

ctrl-r status will walk back up your history looking at each time the command line contained status - just hit return when you find the command you need.

 

Really cool! Just learned about $_.

If anyone wants, I just created a function to perform the first item on the list in a single command.

function mdcd {
    command mkdir $1 && cd $1
}

This should work with bash and zsh, and should be added to their config files(.bashrc and .zshrc, respectively).

 

My favorite piece of knowledge:

If you choose to make an alias for sudo, you should ensure there is a space at the end, or else the shell will not expand any more aliases within the command.

So if I wanted to use please instead of sudo, I would need to do:

alias please="sudo "

I am always tempted to put spaces around the equals sign, probably my #1 scripting mistake.

 

ctrl+r to search back through your command history to rerun a command is something that I find surprises people

vim folks will also love setting vi as the keyboard shortcuts to edit lines in Bash with set -o v within their profile. you can then up arrow (or ctrl+r) to find a previous command, hit Esc to exit insert mode to activate vi shortcuts then to edit the line. For example command 0 (zero) takes you to the beginning of the line, w jumps over words, r will let you overwrite, a to start appending, d3w will delete three words. Using vi shortcuts can save a serious amount of typing.

Folks on windows who like bash and who use visual studio code might like my post on setting Git Bash to be the built in terminal within VS Code.

 

Just a heads up, globbing in your "backup every file" example will miss all dotfiles. You could do a dual expansion in this case for i in * .*; do echo "${i}"; done but this also includes . and .. in this glob. YMMV depending on what you're doing with the list.

 
 

Some of my regular bash commands:

A simple way to monitor network connectivity and latency -- ping a highly-available domain like google.com:

ping google.com | while read pong; do echo "$(date): $pong"; done

I also like to use alias to shorten frequently-used commands and parameters. Here are some examples from my .bashrc:

alias l="ls -aF"
alias ll="ls -laF"
alias c="cd"
alias m="more"
alias e="env | sort"
alias h='history'
alias p="pwd"
alias g="go run"
alias cd..='cd ..'
alias c..='cd ..'
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias .....='cd ../../../..'
alias ......='cd ../../../../..'

Print each PATH entry on a separate line:

alias path='echo -e ${PATH//:/\n}'

Open the current directory in macOS Finder:

alias o="open ."

 

Thanks for these, sometimes it's the little things that you forget and need to read to be reminded. The create folder and change to it is priceless, I turned my one into a function so I can use it generically.

 

In number 3, is moving every file in a folder just an example to illustrate using a for loop? Or is there a reason why you wouldn't do it like this:

mv * ../elsewhere/
 

Haha, no.

I updated it to a more legitimate use. I didn't actually want to use the example of making backups twice in a row, but the moving example didn't make sense. 🙃

 
 

When using mkdir to create /foo/bar adding -p makes sure that /foo is also created if is does not exist yet.

 

For point number 2, does it expand to

cp /some/path/to/file.txt /some/path/to/file.bak

?

If so, shouldn't it be

cp /some/path/to/file{.txt,.bak}

?

 

I guess the author wished to only add a suffix, not change the extension itself.

$ echo /some/path/to/file.txt{,.bak}
/some/path/to/file.txt /some/path/to/file.txt.bak
 

Either one works here. I usually leave the original file extension on these!

code of conduct - report abuse