Bash Commands That Save Me Time and Frustration
Bash Commands That Save Me Time and Frustration
Here’s a list of bash commands that stand between me and insanity.

This article will be accompanied by the following github repository which will contain all the commands listed as well as folders that demonstrate before and after usage!
to accompany the medium article I am writing. Contribute to bgoonz/bash-commands-walkthrough development by creating an…github.com
The readme for this git repo will provide a much more condensed list… whereas this article will break up the commands with explanations… images & links!
I will include the code examples as both github gists (for proper syntax highlighting) and as code snippets adjacent to said gists so that they can easily be copied and pasted… or … if you’re like me for instance; and like to use an extension to grab the markdown content of a page… the code will be included rather than just a link to the gist!

Here’s a Cheatsheet:
#!/bin/bash | |
############################################################################## | |
# SHORTCUTS and HISTORY | |
############################################################################## | |
CTRL+A # move to beginning of line | |
CTRL+B # moves backward one character | |
CTRL+C # halts the current command | |
CTRL+D # deletes one character backward or logs out of current session, similar to exit | |
CTRL+E # moves to end of line | |
CTRL+F # moves forward one character | |
CTRL+G # aborts the current editing command and ring the terminal bell | |
CTRL+H # deletes one character under cursor (same as DELETE) | |
CTRL+J # same as RETURN | |
CTRL+K # deletes (kill) forward to end of line | |
CTRL+L # clears screen and redisplay the line | |
CTRL+M # same as RETURN | |
CTRL+N # next line in command history | |
CTRL+O # same as RETURN, then displays next line in history file | |
CTRL+P # previous line in command history | |
CTRL+Q # resumes suspended shell output | |
CTRL+R # searches backward | |
CTRL+S # searches forward or suspends shell output | |
CTRL+T # transposes two characters | |
CTRL+U # kills backward from point to the beginning of line | |
CTRL+V # makes the next character typed verbatim | |
CTRL+W # kills the word behind the cursor | |
CTRL+X # lists the possible filename completions of the current word | |
CTRL+Y # retrieves (yank) last item killed | |
CTRL+Z # stops the current command, resume with fg in the foreground or bg in the background | |
ALT+B # moves backward one word | |
ALT+D # deletes next word | |
ALT+F # moves forward one word | |
ALT+H # deletes one character backward | |
ALT+T # transposes two words | |
ALT+. # pastes last word from the last command. Pressing it repeatedly traverses through command history. | |
ALT+U # capitalizes every character from the current cursor position to the end of the word | |
ALT+L # uncapitalizes every character from the current cursor position to the end of the word | |
ALT+C # capitalizes the letter under the cursor. The cursor then moves to the end of the word. | |
ALT+R # reverts any changes to a command you’ve pulled from your history if you’ve edited it. | |
ALT+? # list possible completions to what is typed | |
ALT+^ # expand line to most recent match from history | |
CTRL+X then ( # start recording a keyboard macro | |
CTRL+X then ) # finish recording keyboard macro | |
CTRL+X then E # recall last recorded keyboard macro | |
CTRL+X then CTRL+E # invoke text editor (specified by $EDITOR) on current command line then execute resultes as shell commands | |
BACKSPACE # deletes one character backward | |
DELETE # deletes one character under cursor | |
history # shows command line history | |
!! # repeats the last command | |
!<n> # refers to command line 'n' | |
!<string> # refers to command starting with 'string' | |
exit # logs out of current session | |
############################################################################## | |
# BASH BASICS | |
############################################################################## | |
env # displays all environment variables | |
echo $SHELL # displays the shell you're using | |
echo $BASH_VERSION # displays bash version | |
bash # if you want to use bash (type exit to go back to your previously opened shell) | |
whereis bash # locates the binary, source and manual-page for a command | |
which bash # finds out which program is executed as 'bash' (default: /bin/bash, can change across environments) | |
clear # clears content on window (hide displayed lines) | |
############################################################################## | |
# FILE COMMANDS | |
############################################################################## | |
ls # lists your files in current directory, ls <dir> to print files in a specific directory | |
ls -l # lists your files in 'long format', which contains the exact size of the file, who owns the file and who has the right to look at it, and when it was last modified | |
ls -a # lists all files in 'long format', including hidden files (name beginning with '.') | |
ln -s <filename> <link> # creates symbolic link to file | |
readlink <filename> # shows where a symbolic links points to | |
tree # show directories and subdirectories in easilly readable file tree | |
mc # terminal file explorer (alternative to ncdu) | |
touch <filename> # creates or updates (edit) your file | |
mktemp -t <filename> # make a temp file in /tmp/ which is deleted at next boot (-d to make directory) | |
cat <filename> # prints file raw content (will not be interpreted) | |
any_command > <filename> # '>' is used to perform redirections, it will set any_command's stdout to file instead of "real stdout" (generally /dev/stdout) | |
more <filename> # shows the first part of a file (move with space and type q to quit) | |
head <filename> # outputs the first lines of file (default: 10 lines) | |
tail <filename> # outputs the last lines of file (useful with -f option) (default: 10 lines) | |
vim <filename> # opens a file in VIM (VI iMproved) text editor, will create it if it doesn't exist | |
mv <filename1> <dest> # moves a file to destination, behavior will change based on 'dest' type (dir: file is placed into dir; file: file will replace dest (tip: useful for renaming)) | |
cp <filename1> <dest> # copies a file | |
rm <filename> # removes a file | |
find . -name <name> <type> # searches for a file or a directory in the current directory and all its sub-directories by its name | |
diff <filename1> <filename2> # compares files, and shows where they differ | |
wc <filename> # tells you how many lines, words and characters there are in a file. Use -lwc (lines, word, character) to ouput only 1 of those informations | |
sort <filename> # sorts the contents of a text file line by line in alphabetical order, use -n for numeric sort and -r for reversing order. | |
sort -t -k <filename> # sorts the contents on specific sort key field starting from 1, using the field separator t. | |
rev # reverse string characters (hello becomes olleh) | |
chmod -options <filename> # lets you change the read, write, and execute permissions on your files (more infos: SUID, GUID) | |
gzip <filename> # compresses files using gzip algorithm | |
gunzip <filename> # uncompresses files compressed by gzip | |
gzcat <filename> # lets you look at gzipped file without actually having to gunzip it | |
lpr <filename> # prints the file | |
lpq # checks out the printer queue | |
lprm <jobnumber> # removes something from the printer queue | |
genscript # converts plain text files into postscript for printing and gives you some options for formatting | |
dvips <filename> # prints .dvi files (i.e. files produced by LaTeX) | |
grep <pattern> <filenames> # looks for the string in the files | |
grep -r <pattern> <dir> # search recursively for pattern in directory | |
head -n file_name | tail +n # Print nth line from file. | |
head -y lines.txt | tail +x # want to display all the lines from x to y. This includes the xth and yth lines. | |
############################################################################## | |
# DIRECTORY COMMANDS | |
############################################################################## | |
mkdir <dirname> # makes a new directory | |
rmdir <dirname> # remove an empty directory | |
rmdir -rf <dirname> # remove a non-empty directory | |
mv <dir1> <dir2> # rename a directory from <dir1> to <dir2> | |
cd # changes to home | |
cd .. # changes to the parent directory | |
cd <dirname> # changes directory | |
cp -r <dir1> <dir2> # copy <dir1> into <dir2> including sub-directories | |
pwd # tells you where you currently are | |
cd ~ # changes to home. | |
cd - # changes to previous working directory | |
############################################################################## | |
# SSH, SYSTEM INFO & NETWORK COMMANDS | |
############################################################################## | |
ssh user@host # connects to host as user | |
ssh -p <port> user@host # connects to host on specified port as user | |
ssh-copy-id user@host # adds your ssh key to host for user to enable a keyed or passwordless login | |
whoami # returns your username | |
passwd # lets you change your password | |
quota -v # shows what your disk quota is | |
date # shows the current date and time | |
cal # shows the month's calendar | |
uptime # shows current uptime | |
w # displays whois online | |
finger <user> # displays information about user | |
uname -a # shows kernel information | |
man <command> # shows the manual for specified command | |
df # shows disk usage | |
du <filename> # shows the disk usage of the files and directories in filename (du -s give only a total) | |
last <yourUsername> # lists your last logins | |
ps -u yourusername # lists your processes | |
kill <PID> # kills the processes with the ID you gave | |
killall <processname> # kill all processes with the name | |
top # displays your currently active processes | |
lsof # lists open files | |
bg # lists stopped or background jobs ; resume a stopped job in the background | |
fg # brings the most recent job in the foreground | |
fg <job> # brings job to the foreground | |
ping <host> # pings host and outputs results | |
whois <domain> # gets whois information for domain | |
dig <domain> # gets DNS information for domain | |
dig -x <host> # reverses lookup host | |
wget <file> # downloads file | |
time <command> # report time consumed by command execution | |
############################################################################## | |
# VARIABLES | |
############################################################################## | |
varname=value # defines a variable | |
varname=value command # defines a variable to be in the environment of a particular subprocess | |
echo $varname # checks a variable's value | |
echo $$ # prints process ID of the current shell | |
echo $! # prints process ID of the most recently invoked background job | |
echo $? # displays the exit status of the last command | |
read <varname> # reads a string from the input and assigns it to a variable | |
read -p "prompt" <varname> # same as above but outputs a prompt to ask user for value | |
column -t <filename> # display info in pretty columns (often used with pipe) | |
let <varname> = <equation> # performs mathematical calculation using operators like +, -, *, /, % | |
export VARNAME=value # defines an environment variable (will be available in subprocesses) | |
array[0]=valA # how to define an array | |
array[1]=valB | |
array[2]=valC | |
array=([2]=valC [0]=valA [1]=valB) # another way | |
array=(valA valB valC) # and another | |
${array[i]} # displays array's value for this index. If no index is supplied, array element 0 is assumed | |
${#array[i]} # to find out the length of any element in the array | |
${#array[@]} # to find out how many values there are in the array | |
declare -a # the variables are treated as arrays | |
declare -f # uses function names only | |
declare -F # displays function names without definitions | |
declare -i # the variables are treated as integers | |
declare -r # makes the variables read-only | |
declare -x # marks the variables for export via the environment | |
${varname:-word} # if varname exists and isn't null, return its value; otherwise return word | |
${varname:word} # if varname exists and isn't null, return its value; otherwise return word | |
${varname:=word} # if varname exists and isn't null, return its value; otherwise set it word and then return its value | |
${varname:?message} # if varname exists and isn't null, return its value; otherwise print varname, followed by message and abort the current command or script | |
${varname:+word} # if varname exists and isn't null, return word; otherwise return null | |
${varname:offset:length} # performs substring expansion. It returns the substring of $varname starting at offset and up to length characters | |
${variable#pattern} # if the pattern matches the beginning of the variable's value, delete the shortest part that matches and return the rest | |
${variable##pattern} # if the pattern matches the beginning of the variable's value, delete the longest part that matches and return the rest | |
${variable%pattern} # if the pattern matches the end of the variable's value, delete the shortest part that matches and return the rest | |
${variable%%pattern} # if the pattern matches the end of the variable's value, delete the longest part that matches and return the rest | |
${variable/pattern/string} # the longest match to pattern in variable is replaced by string. Only the first match is replaced | |
${variable//pattern/string} # the longest match to pattern in variable is replaced by string. All matches are replaced | |
${#varname} # returns the length of the value of the variable as a character string | |
*(patternlist) # matches zero or more occurrences of the given patterns | |
+(patternlist) # matches one or more occurrences of the given patterns | |
?(patternlist) # matches zero or one occurrence of the given patterns | |
@(patternlist) # matches exactly one of the given patterns | |
!(patternlist) # matches anything except one of the given patterns | |
$(UNIX command) # command substitution: runs the command and returns standard output | |
############################################################################## | |
# FUNCTIONS | |
############################################################################## | |
# The function refers to passed arguments by position (as if they were positional parameters), that is, $1, $2, and so forth. | |
# $@ is equal to "$1" "$2"... "$N", where N is the number of positional parameters. $# holds the number of positional parameters. | |
function functname() { | |
shell commands | |
} | |
unset -f functname # deletes a function definition | |
declare -f # displays all defined functions in your login session | |
############################################################################## | |
# FLOW CONTROLS | |
############################################################################## | |
statement1 && statement2 # and operator | |
statement1 || statement2 # or operator | |
-a # and operator inside a test conditional expression | |
-o # or operator inside a test conditional expression | |
# STRINGS | |
str1 == str2 # str1 matches str2 | |
str1 != str2 # str1 does not match str2 | |
str1 < str2 # str1 is less than str2 (alphabetically) | |
str1 > str2 # str1 is greater than str2 (alphabetically) | |
str1 \> str2 # str1 is sorted after str2 | |
str1 \< str2 # str1 is sorted before str2 | |
-n str1 # str1 is not null (has length greater than 0) | |
-z str1 # str1 is null (has length 0) | |
# FILES | |
-a file # file exists or its compilation is successful | |
-d file # file exists and is a directory | |
-e file # file exists; same -a | |
-f file # file exists and is a regular file (i.e., not a directory or other special type of file) | |
-r file # you have read permission | |
-s file # file exists and is not empty | |
-w file # your have write permission | |
-x file # you have execute permission on file, or directory search permission if it is a directory | |
-N file # file was modified since it was last read | |
-O file # you own file | |
-G file # file's group ID matches yours (or one of yours, if you are in multiple groups) | |
file1 -nt file2 # file1 is newer than file2 | |
file1 -ot file2 # file1 is older than file2 | |
# NUMBERS | |
-lt # less than | |
-le # less than or equal | |
-eq # equal | |
-ge # greater than or equal | |
-gt # greater than | |
-ne # not equal | |
if condition | |
then | |
statements | |
[elif condition | |
then statements...] | |
[else | |
statements] | |
fi | |
for x in {1..10} | |
do | |
statements | |
done | |
for name [in list] | |
do | |
statements that can use $name | |
done | |
for (( initialisation ; ending condition ; update )) | |
do | |
statements... | |
done | |
case expression in | |
pattern1 ) | |
statements ;; | |
pattern2 ) | |
statements ;; | |
esac | |
select name [in list] | |
do | |
statements that can use $name | |
done | |
while condition; do | |
statements | |
done | |
until condition; do | |
statements | |
done | |
############################################################################## | |
# COMMAND-LINE PROCESSING CYCLE | |
############################################################################## | |
# The default order for command lookup is functions, followed by built-ins, with scripts and executables last. | |
# There are three built-ins that you can use to override this order: `command`, `builtin` and `enable`. | |
command # removes alias and function lookup. Only built-ins and commands found in the search path are executed | |
builtin # looks up only built-in commands, ignoring functions and commands found in PATH | |
enable # enables and disables shell built-ins | |
eval # takes arguments and run them through the command-line processing steps all over again | |
############################################################################## | |
# INPUT/OUTPUT REDIRECTORS | |
############################################################################## | |
cmd1|cmd2 # pipe; takes standard output of cmd1 as standard input to cmd2 | |
< file # takes standard input from file | |
> file # directs standard output to file | |
>> file # directs standard output to file; append to file if it already exists | |
>|file # forces standard output to file even if noclobber is set | |
n>|file # forces output to file from file descriptor n even if noclobber is set | |
<> file # uses file as both standard input and standard output | |
n<>file # uses file as both input and output for file descriptor n | |
n>file # directs file descriptor n to file | |
n<file # takes file descriptor n from file | |
n>>file # directs file description n to file; append to file if it already exists | |
n>& # duplicates standard output to file descriptor n | |
n<& # duplicates standard input from file descriptor n | |
n>&m # file descriptor n is made to be a copy of the output file descriptor | |
n<&m # file descriptor n is made to be a copy of the input file descriptor | |
&>file # directs standard output and standard error to file | |
<&- # closes the standard input | |
>&- # closes the standard output | |
n>&- # closes the ouput from file descriptor n | |
n<&- # closes the input from file descripor n | |
|tee <file># output command to both terminal and a file (-a to append to file) | |
############################################################################## | |
# PROCESS HANDLING | |
############################################################################## | |
# To suspend a job, type CTRL+Z while it is running. You can also suspend a job with CTRL+Y. | |
# This is slightly different from CTRL+Z in that the process is only stopped when it attempts to read input from terminal. | |
# Of course, to interrupt a job, type CTRL+C. | |
myCommand & # runs job in the background and prompts back the shell | |
jobs # lists all jobs (use with -l to see associated PID) | |
fg # brings a background job into the foreground | |
fg %+ # brings most recently invoked background job | |
fg %- # brings second most recently invoked background job | |
fg %N # brings job number N | |
fg %string # brings job whose command begins with string | |
fg %?string # brings job whose command contains string | |
kill -l # returns a list of all signals on the system, by name and number | |
kill PID # terminates process with specified PID | |
kill -s SIGKILL 4500 # sends a signal to force or terminate the process | |
kill -15 913 # Ending PID 913 process with signal 15 (TERM) | |
kill %1 # Where %1 is the number of job as read from 'jobs' command. | |
ps # prints a line of information about the current running login shell and any processes running under it | |
ps -a # selects all processes with a tty except session leaders | |
trap cmd sig1 sig2 # executes a command when a signal is received by the script | |
trap "" sig1 sig2 # ignores that signals | |
trap - sig1 sig2 # resets the action taken when the signal is received to the default | |
disown <PID|JID> # removes the process from the list of jobs | |
wait # waits until all background jobs have finished | |
sleep <number> # wait # of seconds before continuing | |
pv # display progress bar for data handling commands. often used with pipe like |pv | |
yes # give yes response everytime an input is requested from script/process | |
############################################################################## | |
# TIPS & TRICKS | |
############################################################################## | |
# set an alias | |
cd; nano .bash_profile | |
> alias gentlenode='ssh admin@gentlenode.com -p 3404' # add your alias in .bash_profile | |
# to quickly go to a specific directory | |
cd; nano .bashrc | |
> shopt -s cdable_vars | |
> export websites="/Users/mac/Documents/websites" | |
source .bashrc | |
cd $websites | |
############################################################################## | |
# DEBUGGING SHELL PROGRAMS | |
############################################################################## | |
bash -n scriptname # don't run commands; check for syntax errors only | |
set -o noexec # alternative (set option in script) | |
bash -v scriptname # echo commands before running them | |
set -o verbose # alternative (set option in script) | |
bash -x scriptname # echo commands after command-line processing | |
set -o xtrace # alternative (set option in script) | |
trap 'echo $varname' EXIT # useful when you want to print out the values of variables at the point that your script exits | |
function errtrap { | |
es=$? | |
echo "ERROR line $1: Command exited with status $es." | |
} | |
trap 'errtrap $LINENO' ERR # is run whenever a command in the surrounding script or function exits with non-zero status | |
function dbgtrap { | |
echo "badvar is $badvar" | |
} | |
trap dbgtrap DEBUG # causes the trap code to be executed before every statement in a function or script | |
# ...section of code in which the problem occurs... | |
trap - DEBUG # turn off the DEBUG trap | |
function returntrap { | |
echo "A return occurred" | |
} | |
trap returntrap RETURN # is executed each time a shell function or a script executed with the . or source commands finishes executing | |
############################################################################## | |
# COLORS AND BACKGROUNDS | |
############################################################################## | |
# note: \e or \x1B also work instead of \033 | |
# Reset | |
Color_Off='\033[0m' # Text Reset | |
# Regular Colors | |
Black='\033[0;30m' # Black | |
Red='\033[0;31m' # Red | |
Green='\033[0;32m' # Green | |
Yellow='\033[0;33m' # Yellow | |
Blue='\033[0;34m' # Blue | |
Purple='\033[0;35m' # Purple | |
Cyan='\033[0;36m' # Cyan | |
White='\033[0;97m' # White | |
# Additional colors | |
LGrey='\033[0;37m' # Ligth Gray | |
DGrey='\033[0;90m' # Dark Gray | |
LRed='\033[0;91m' # Ligth Red | |
LGreen='\033[0;92m' # Ligth Green | |
LYellow='\033[0;93m'# Ligth Yellow | |
LBlue='\033[0;94m' # Ligth Blue | |
LPurple='\033[0;95m'# Light Purple | |
LCyan='\033[0;96m' # Ligth Cyan | |
# Bold | |
BBlack='\033[1;30m' # Black | |
BRed='\033[1;31m' # Red | |
BGreen='\033[1;32m' # Green | |
BYellow='\033[1;33m'# Yellow | |
BBlue='\033[1;34m' # Blue | |
BPurple='\033[1;35m'# Purple | |
BCyan='\033[1;36m' # Cyan | |
BWhite='\033[1;37m' # White | |
# Underline | |
UBlack='\033[4;30m' # Black | |
URed='\033[4;31m' # Red | |
UGreen='\033[4;32m' # Green | |
UYellow='\033[4;33m'# Yellow | |
UBlue='\033[4;34m' # Blue | |
UPurple='\033[4;35m'# Purple | |
UCyan='\033[4;36m' # Cyan | |
UWhite='\033[4;37m' # White | |
# Background | |
On_Black='\033[40m' # Black | |
On_Red='\033[41m' # Red | |
On_Green='\033[42m' # Green | |
On_Yellow='\033[43m'# Yellow | |
On_Blue='\033[44m' # Blue | |
On_Purple='\033[45m'# Purple | |
On_Cyan='\033[46m' # Cyan | |
On_White='\033[47m' # White | |
# Example of usage | |
echo -e "${Green}This is GREEN text${Color_Off} and normal text" | |
echo -e "${Red}${On_White}This is Red test on White background${Color_Off}" | |
# option -e is mandatory, it enable interpretation of backslash escapes | |
printf "${Red} This is red \n" |
Getting Started (Advanced Users Skip Section):
✔ Check the Current Directory ➡ pwd
:
On the command line, it’s important to know the directory we are
currently working on. For that, we can use
pwd
command.

It shows that I’m working on my Desktop directory.
✔ Display List of Files ➡ ls
:
To see the list of files and directories in the current
directory use
ls
command in
your CLI.

Shows all of my files and directories of my Desktop directory.
-
To show the contents of a directory pass the directory name to
the
ls
command i.e.ls directory_name
. -
Some useful
ls
command options:-
OptionDescriptionls -alist all files including hidden file starting with ‘.’ls -llist with the long formatls -lalist long format including hidden files
✔ Create a Directory ➡ mkdir
:
We can create a new folder using the
mkdir
command.
To use it type
mkdir folder_name
.

Use ls
command
to see the directory is created or not.
I created a cli-practice directory in my working directory i.e. Desktop directory.
✔ Move Between Directories ➡ cd
:
It’s used to change directory or to move other directories. To
use it type
cd directory_name
.

Can use
pwd
command to
confirm your directory name.
Changed my directory to the cli-practice directory. And the rest of the tutorial I’m gonna work within this directory.
✔ Parent Directory ➡ ..
:
We have seen
cd
command to
change directory but if we want to move back or want to move to
the parent directory we can use a special symbol ..
after
cd
command,
like cd ..
✔ Create Files ➡ touch
:
We can create an empty file by typing
touch file_name
. It's going to create a new file in the current directory
(the directory you are currently in) with your provided name.

I created a hello.txt file in my current working directory.
Again you can use
ls
command to
see the file is created or not.
Now open your hello.txt file in your text editor and write Hello Everyone! into your hello.txt file and save it.
✔ Display the Content of a File ➡ cat
:
We can display the content of a file using the
cat
command. To
use it type
cat file_name
.

Shows the content of my hello.txt file.
✔ Move Files & Directories ➡ mv
:
To move a file and directory, we use
mv
command.
By typing
mv file_to_move destination_directory
, you can move a file to the specified directory.
By entering
mv directory_to_move destination_directory
, you can move all the files and directories under that
directory.
Before using this command, we are going to create two more directories and another txt file in our cli-practice directory.
mkdir html css touch bye.txt

Yes, we can use multiple directories & files names one after another to create multiple directories & files in one command.

Moved my bye.txt file into my css directory and then moved my css directory into my html directory.
✔ Rename Files & Directories ➡ mv
:
mv
command can
also be used to rename a file and a directory.
You can rename a file by typing
mv old_file_name new_file_name
& also rename a directory by typing
mv old_directory_name new_directory_name
.

Renamed my hello.txt file to the hi.txt file and html directory to the folder directory.
✔ Copy Files & Directories ➡ cp
:
To do this, we use the
cp
command.
-
You can copy a file by entering
cp file_to_copy new_file_name
.

Copied my hi.txt file content into hello.txt file. For confirmation open your hello.txt file in your text editor.
-
You can also copy a directory by adding the
-r
option, likecp -r directory_to_copy new_directory_name
.
The -r
option for "recursive" means that it will copy all
of the files including the files inside of subfolders.

Here I copied all of the files from the folder to folder-copy.
✔ Remove Files & Directories ➡ rm
:
To do this, we use the
rm
command.
-
To remove a file, you can use the command like
rm file_to_remove
.

Here I removed my hi.txt file.
-
To remove a directory, use the command like
rm -r directory_to_remove
.

I removed my folder-copy directory from my cli-practice directory i.e. current working directory.
✔ Clear Screen ➡ clear
:
Clear command is used to clear the terminal screen.
✔ Home Directory ➡ ~
:
The Home directory is represented by
~
. The Home
directory refers to the base directory for the user. If we want
to move to the Home directory we can use
cd ~
command.
Or we can only use
cd
command.
MY COMMANDS:
1.) Recursively unzip zip files and then delete the archives when finished:
here is a folder containing the before and after… I had to change folder names slightly due to a limit on the length of file-paths in a github repo.
find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done;
find . -name "*.zip" -type f -print -delete
# Recursively unzip zip files and then delete the archives when finished | |
sudo apt install unzip | |
find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done; | |
find . -name "*.zip" -type f -print -delete |
2.) Install node modules recursively:
npm i -g recursive-install
npm-recursive-install
npm i -g recursive-install | |
npm-recursive-install |
3.) Clean up unnecessary files/folders in git repo:
find . -empty -type f -print -delete #Remove empty files
# -------------------------------------------------------
find . -empty -type d -print -delete #Remove empty folders
# -------------------------------------------------------
# This will remove .git folders... .gitmodule files as well as .gitattributes and .gitignore files.
find . \( -name ".git" -o -name ".gitignore" -o -name ".gitmodules" -o -name ".gitattributes" \) -exec rm -rf -- {} +
# -------------------------------------------------------
# This will remove the filenames you see listed below that just take up space if a repo has been downloaded for use exclusively in your personal file system (in which case the following files just take up space)# Disclaimer... you should not use this command in a repo that you intend to use with your work as it removes files that attribute the work to their original creators!
find . \( -name "*SECURITY.txt" -o -name "*RELEASE.txt" -o -name "*CHANGELOG.txt" -o -name "*LICENSE.txt" -o -name "*CONTRIBUTING.txt" -name "*HISTORY.md" -o -name "*LICENSE" -o -name "*SECURITY.md" -o -name "*RELEASE.md" -o -name "*CHANGELOG.md" -o -name "*LICENSE.md" -o -name "*CODE_OF_CONDUCT.md" -o -name "\*CONTRIBUTING.md" \) -exec rm -rf -- {} +
# Recursivley delete empty files. | |
find . -empty -type f -print -delete |
# Recursively delete empty folders: | |
find . -empty -type d -print -delete |
# This will remove .git folders... .gitmodule files as well as .gitattributes and .gitignore files. | |
find . \( -name ".git" -o -name ".gitignore" -o -name ".gitmodules" -o -name ".gitattributes" \) -exec rm -rf -- {} + | |
# This will remove the filenames you see listed below that just take up space if a repo has been downloaded for use exclusivley in your personal file system (in which case the following files just take up space) | |
# Disclaimer... you should not use this command in a repo that you intend to use with your work as it removes files that attribute the work to their original creators! | |
find . \( -name "*SECURITY.txt" -o -name "*RELEASE.txt" -o -name "*CHANGELOG.txt" -o -name "*LICENSE.txt" -o -name "*CONTRIBUTING.txt" -name "*HISTORY.md" -o -name "*LICENSE" -o -name "*SECURITY.md" -o -name "*RELEASE.md" -o -name "*CHANGELOG.md" -o -name "*LICENSE.md" -o -name "*CODE_OF_CONDUCT.md" -o -name "\*CONTRIBUTING.md" \) -exec rm -rf -- {} + |
In Action:
The following output from my bash shell corresponds to the directory:
Deployment github-pages Navigation Big O notation is the language we use for talking about how long an algorithm takes…github.com
which was created by running the aforementioned commands in in a perfect copy of this directory:
Deployment github-pages Navigation Big O notation is the language we use for talking about how long an algorithm takes…github.com
…..below is the terminal output for the following commands:
pwd
/mnt/c/Users/bryan/Downloads/bash-commands/steps/3-clean-up-fluf/DS-ALGO-OFFICIAL-master
After printing the working directory for good measure:
find . -empty -type f -print -delete
The above command deletes empty files recursively starting from the directory in which it was run:
./CONTENT/DS-n-Algos/File-System/file-utilities/node_modules/line-reader/test/data/empty_file.txt
./CONTENT/DS-n-Algos/_Extra-Practice/free-code-camp/nodejs/http-collect.js
./CONTENT/Resources/Comments/node_modules/mime/.npmignore
./markdown/tree2.md
./node_modules/loadashes6/lodash/README.md
./node_modules/loadashes6/lodash/release.md
./node_modules/web-dev-utils/Markdown-Templates/Markdown-Templates-master/filled-out-readme.md
|01:33:16|bryan@LAPTOP-9LGJ3JGS:[DS-ALGO-OFFICIAL-master] DS-ALGO-OFFICIAL-master_exitstatus:0[╗___________o>
The command seen below deletes empty folders recursively starting from the directory in which it was run:
find . -empty -type d -print -delete
The resulting directories….
|01:33:16|bryan@LAPTOP-9LGJ3JGS:[DS-ALGO-OFFICIAL-master] DS-ALGO-OFFICIAL-master_exitstatus:0[╗___________o>
find . -empty -type d -print -delete
./.git/branches
./.git/objects/info
./.git/refs/tags
|01:33:31|bryan@LAPTOP-9LGJ3JGS:[DS-ALGO-OFFICIAL-master] DS-ALGO-OFFICIAL-master_exitstatus:0[╗___________o>
The command seen below deletes .git folders as well as .gitignore, .gitattributes, .gitmodule files
find . \( -name ".git" -o -name ".gitignore" -o -name ".gitmodules" -o -name ".gitattributes" \) -exec rm -rf -- {} +
The command seen below deletes most SECURITY, RELEASE, CHANGELOG, LICENSE, CONTRIBUTING, & HISTORY files that take up pointless space in repo’s you wish to keep exclusively for your own reference.
!!!Use with caution as this command removes the attribution of the work from it’s original authors!!!!!
find . \( -name "*SECURITY.txt" -o -name "*RELEASE.txt" -o -name "*CHANGELOG.txt" -o -name "*LICENSE.txt" -o -name "*CONTRIBUTING.txt" -name "*HISTORY.md" -o -name "*LICENSE" -o -name "*SECURITY.md" -o -name "*RELEASE.md" -o -name "*CHANGELOG.md" -o -name "*LICENSE.md" -o -name "*CODE_OF_CONDUCT.md" -o -name "*CONTRIBUTING.md" \) -exec rm -rf -- {} +
4.) Generate index.html file that links to all other files in working directory:
#!/bin/sh
# find ./ | grep -i "\.*$" >files
find ./ | sed -E -e 's/([^ ]+[ ]+){8}//' | grep -i "\.*$">files
listing="files"
out=""
html="index.html"
out="basename $out.html"
html="index.html"
cmd() {
echo ' <!DOCTYPE html>'
echo '<html>'
echo '<head>'
echo ' <meta http-equiv="Content-Type" content="text/html">'
echo ' <meta name="Author" content="Bryan Guner">'
echo '<link rel="stylesheet" href="./assets/prism.css">'
echo ' <link rel="stylesheet" href="./assets/style.css">'
echo ' <script async defer src="./assets/prism.js"></script>'
echo " <title> directory </title>"
echo ""
echo '<style>'
echo ' a {'
echo ' color: black;'
echo ' }'
echo ''
echo ' li {'
echo ' border: 1px solid black !important;'
echo ' font-size: 20px;'
echo ' letter-spacing: 0px;'
echo ' font-weight: 700;'
echo ' line-height: 16px;'
echo ' text-decoration: none !important;'
echo ' text-transform: uppercase;'
echo ' background: #194ccdaf !important;'
echo ' color: black !important;'
echo ' border: none;'
echo ' cursor: pointer;'
echo ' justify-content: center;'
echo ' padding: 30px 60px;'
echo ' height: 48px;'
echo ' text-align: center;'
echo ' white-space: normal;'
echo ' border-radius: 10px;'
echo ' min-width: 45em;'
echo ' padding: 1.2em 1em 0;'
echo ' box-shadow: 0 0 5px;'
echo ' margin: 1em;'
echo ' display: grid;'
echo ' -webkit-border-radius: 10px;'
echo ' -moz-border-radius: 10px;'
echo ' -ms-border-radius: 10px;'
echo ' -o-border-radius: 10px;'
echo ' }'
echo ' </style>'
echo '</head>'
echo '<body>'
echo ""
# continue with the HTML stuff
echo ""
echo ""
echo "<ul>"
awk '{print "<li><a href=\""$1"\">",$1," </a></li>"}' $listing
# awk '{print "<li>"};
# {print " <a href=\""$1"\">",$1,"</a></li> "}' \ $listing
echo ""
echo "</ul>"
echo "</body>"
echo "</html>"
}
cmd $listing --sort=extension >>$html
#!/bin/sh | |
# find ./ | grep -i "\.\*$" >files | |
find ./ | sed -E -e 's/([^ ]+[ ]+){8}//' | grep -i "\.\*$">files | |
listing="files" | |
out="" | |
html="index.html" | |
out="basename $out.html" | |
html="index.html" | |
cmd() { | |
echo ' <!DOCTYPE html>' | |
echo '<html>' | |
echo '<head>' | |
echo ' <meta http-equiv="Content-Type" content="text/html">' | |
echo ' <meta name="Author" content="Bryan Guner">' | |
echo '<link rel="stylesheet" href="./assets/prism.css">' | |
echo ' <link rel="stylesheet" href="./assets/style.css">' | |
echo ' <script async defer src="./assets/prism.js"></script>' | |
echo " <title> directory </title>" | |
echo "" | |
echo '<style>' | |
echo ' a {' | |
echo ' color: black;' | |
echo ' }' | |
echo '' | |
echo ' li {' | |
echo ' border: 1px solid black !important;' | |
echo ' font-size: 20px;' | |
echo ' letter-spacing: 0px;' | |
echo ' font-weight: 700;' | |
echo ' line-height: 16px;' | |
echo ' text-decoration: none !important;' | |
echo ' text-transform: uppercase;' | |
echo ' background: #194ccdaf !important;' | |
echo ' color: black !important;' | |
echo ' border: none;' | |
echo ' cursor: pointer;' | |
echo ' justify-content: center;' | |
echo ' padding: 30px 60px;' | |
echo ' height: 48px;' | |
echo ' text-align: center;' | |
echo ' white-space: normal;' | |
echo ' border-radius: 10px;' | |
echo ' min-width: 45em;' | |
echo ' padding: 1.2em 1em 0;' | |
echo ' box-shadow: 0 0 5px;' | |
echo ' margin: 1em;' | |
echo ' display: grid;' | |
echo ' -webkit-border-radius: 10px;' | |
echo ' -moz-border-radius: 10px;' | |
echo ' -ms-border-radius: 10px;' | |
echo ' -o-border-radius: 10px;' | |
echo ' }' | |
echo ' </style>' | |
echo '</head>' | |
echo '<body>' | |
echo "" | |
# continue with the HTML stuff | |
echo "" | |
echo "" | |
echo "<ul>" | |
awk '{print "<li><a href=\""$1"\">",$1," </a></li>"}' $listing | |
# awk '{print "<li>"}; | |
# {print " <a href=\""$1"\">",$1,"</a></li> "}' \ $listing | |
echo "" | |
echo "</ul>" | |
echo "</body>" | |
echo "</html>" | |
} | |
cmd $listing --sort=extension >>$html |
In Action:
I will use this copy of my Data Structures Practice Site to demonstrate the result:
Deployment github-pages Navigation Big O notation is the language we use for talking about how long an algorithm takes…github.com

The result is a index.html file that contains a list of links to each file in the directory:
here is a link to and photo of the resulting html file:

5.) Download all links to a files of a specified extension on a user provided (url) webpage:
wget -r -A.pdf https://overapi.com/gitwget --wait=2 --level=inf --limit-rate=20K --recursive --page-requisites --user-agent=Mozilla --no-parent --convert-links --adjust-extension --no-clobber -e robots=off
wget -r -A.pdf https://overapi.com/gitwget --wait=2 --level=inf --limit-rate=20K --recursive --page-requisites --user-agent=Mozilla --no-parent --convert-links --adjust-extension --no-clobber -e robots=off |
The result is stored in this directory:

6.)Recursively remove lines of text containing the string badFolder from files in the working directory.
find . -type f -exec sed -i '/badFolder/d' ./* {} \;
# OR
find . -name 'result.md' -type f -exec sed -i '/badFolder/d' ./* {} \;
# Recursively remove lines of text containing the string badFolder from files in the working directory. | |
find . -type f -exec sed -i '/badFolder/d' ./* {} \; |
# Recursively remove lines of text containing the string badFolder from files named result.md in the working directory. | |
find . -name 'result.md' -type f -exec sed -i '/badFolder/d' ./* {} \; |
As an example I will run this command on a file containing the text:
Hacks Blog
Read more at hacks.mozilla.org
badFolder
badFolder Implementing Private Fields for JavaScript
When implementing a language feature for JavaScript, an implementer must make decisions about how the language in the specification maps to the implementation. Private fields is an example of where the specification language and implementation reality diverge, at least in SpiderMonkey– the JavaScript engine which powers Firefox. To understand more, I’ll explain what private fields are, a couple of models for thinking about them, and explain why our implementation diverges from the specification language.The post Implementing Private Fields for JavaScript appeared first on Mozilla Hacks - the Web developer blog.
Posted Tuesday, June 8, 2021 by Matthew Gaudet
Looking fine with Firefox 89
Firefox 89 has smartened up and brings with it a slimmed-down, slightly more minimalist interface.badFolder Along with this new look, we get some great styling features including a force-colours feature for media queries and better control over how fonts are displayed. The long-awaited top-level await keyword for JavaScript modules is now enabled, as well as the PerformanceEventTiming interface, which is another addition to the performance suite of APIs: 89 really has been working out!The post Looking fine with Firefox 89 appeared first on Mozilla Hacks - the Web developer blog.
badFolder
Posted Tuesday, June 1, 2021 by Chris Mills
badFolder
Improving Firefox stability on Linux
Roughly a year ago at Mozilla we started an effort to improve Firefox stability on Linux. This effort quickly became an example of good synergies between FOSS projects.The post Improving Firefox stability on Linux appeared first on Mozilla Hacks - the Web developer blog.
Posted Wednesday, May 19, 2021 by Gabriele Svelto badFolder
Introducing Firefox’s new Site Isolation Security Architecture
Like any web browser, Firefox loads code from untrusted and potentially hostile websites and runs it on your computer. To protect you against new types of attacks from malicious sites and to meet the security principles of Mozilla, we set out to redesign Firefox on desktop.The post Introducing Firefox’s new Site Isolation Security Architecture appeared first on Mozilla Hacks - the Web developer blog.
Posted Tuesday, May 18, 2021 by Anny Gakhokidze
Pyodide Spin Out and 0.17 Release
We are happy to announce that Pyodide has become an independent and community-driven project. We are also pleased to announce the 0.17 release for Pyodide with many new features and improvements. Pyodide consists of the CPython 3.8 interpreter compiled to WebAssembly which allows Python to run in the browser.The post Pyodide Spin Out and 0.17 Release appeared first on Mozilla Hacks - the Web developer blog. badFolder
Posted Thursday, April 22, 2021 by Teon Brooks
I modified the command slightly to apply only to files called ‘result.md’:
# Recursively remove lines of text containing the string badFolder from files in the working directory. | |
find . -type f -exec sed -i '/badFolder/d' ./* {} \; |
# Recursively remove lines of text containing the string badFolder from files named result.md in the working directory. | |
find . -name 'result.md' -type f -exec sed -i '/badFolder/d' ./* {} \; |
The result is :
Hacks Blog
Read more at hacks.mozilla.org
When implementing a language feature for JavaScript, an implementer must make decisions about how the language in the specification maps to the implementation. Private fields is an example of where the specification language and implementation reality diverge, at least in SpiderMonkey– the JavaScript engine which powers Firefox. To understand more, I’ll explain what private fields are, a couple of models for thinking about them, and explain why our implementation diverges from the specification language.The post Implementing Private Fields for JavaScript appeared first on Mozilla Hacks - the Web developer blog.
Posted Tuesday, June 8, 2021 by Matthew Gaudet
Looking fine with Firefox 89
Posted Tuesday, June 1, 2021 by Chris Mills
Improving Firefox stability on Linux
Roughly a year ago at Mozilla we started an effort to improve Firefox stability on Linux. This effort quickly became an example of good synergies between FOSS projects.The post Improving Firefox stability on Linux appeared first on Mozilla Hacks - the Web developer blog.
Introducing Firefox’s new Site Isolation Security Architecture
Like any web browser, Firefox loads code from untrusted and potentially hostile websites and runs it on your computer. To protect you against new types of attacks from malicious sites and to meet the security principles of Mozilla, we set out to redesign Firefox on desktop.The post Introducing Firefox’s new Site Isolation Security Architecture appeared first on Mozilla Hacks - the Web developer blog.
Posted Tuesday, May 18, 2021 by Anny Gakhokidze
Pyodide Spin Out and 0.17 Release
Posted Thursday, April 22, 2021 by Teon Brooks

the test.txt and result.md files can be found here:
7.) Execute command recursively:
Here I have modified the command I wish to run recursively to account for the fact that the ‘find’ command already works recursively, by appending the -maxdepth 1 flag…
I am essentially removing the recursive action of the find command…
That way, if the command affects the more deeply nested folders we know the outer RecurseDirs function we are using to run the find/pandoc line once in every subfolder of the working directory… is working properly!
function RecurseDirs () | |
{ | |
oldIFS=$IFS | |
IFS=$'\n' | |
for f in "$@" | |
do | |
# YOUR CODE HERE! | |
find ./ -iname "*.md" -maxdepth 1 -type f -exec sh -c 'pandoc --standalone "${0}" -o "${0%.md}.html"' {} \; | |
if [[ -d "${f}" ]]; then | |
cd "${f}" | |
RecurseDirs $(ls -1 ".") | |
cd .. | |
fi | |
done | |
IFS=$oldIFS | |
} | |
RecurseDirs "./" |

Run in the folder shown to the left… we would expect every .md file to be accompanied by a newly generated html file by the same name.
The results of said operation can be found in the following directory
In Action:
🢃 Below 🢃

The final result is:

If you want to run any bash script recursively all you have to do is substitue out line #9 with the command you want to run once in every sub-folder.
function RecurseDirs ()
{
oldIFS=$IFS
IFS=$'\n'
for f in "$@"
do
#Replace the line below with your own command!
#find ./ -iname "*.md" -maxdepth 1 -type f -exec sh -c 'pandoc --standalone "${0}" -o "${0%.md}.html"' {} \;
#####################################################
# YOUR CODE BELOW!
#####################################################
if [[ -d "${f}" ]]; then
cd "${f}"
RecurseDirs $(ls -1 ".")
cd ..
fi
done
IFS=$oldIFS
}
RecurseDirs "./"
TBC….
Here are some of the other commands I will cover in greater detail… at a later time:
9. Copy any text between <script> tags in a file called example.html to be inserted into a new file: out.js
sed -n -e '/<script>/,/<\/script>/p' example.html >out.js
10. Recursively Delete node_modules folders
find . -name 'node_modules' -type d -print -prune -exec rm -rf '{}' +
11. Sanatize file and folder names to remove illegal characters and reserved words.
sanitize() {
shopt -s extglob;
filename=$(basename "$1")
directory=$(dirname "$1")
filename_clean=$(echo "$filename" | sed -e 's/[\\/:\*\?"<>\|\x01-\x1F\x7F]//g' -e 's/^\(nul\|prn\|con\|lpt[0-9]\|com[0-9]\|aux\)\(\.\|$\)//i' -e 's/^\.*$//' -e 's/^$/NONAME/')
if (test "$filename" != "$filename_clean")
then
mv -v "$1" "$directory/$filename_clean"
fi
}
export -f sanitize
sanitize_dir() {
find "$1" -depth -exec bash -c 'sanitize "$0"' {} \;
}
sanitize_dir '/path/to/somewhere'
12. Start postgresql in terminal
sudo -u postgres psql
13. Add closing body and script tags to each html file in working directory.
for f in * ; do
mv "$f" "$f.html"
doneecho "<form>
<input type="button" value="Go back!" onclick="history.back()">
</form>
</body></html>" | tee -a *.html
14. Batch Download Videos
#!/bin/bash
link="#insert url here#"
#links were a set of strings with just the index of the video as the variable
num=3
#first video was numbered 3 - weird.
ext=".mp4"
while [ $num -le 66 ]
do
wget $link$num$ext -P ~/Downloads/
num=$(($num+1))
done
15. Change File Extension from ‘.txt’ to .doc for all files in working directory.
sudo apt install rename
rename 's/\.txt$/.doc/' *.txt
16. Recursivley change any file with extension .js.download to .js
find . -name "*.\.js\.download" -exec rename 's/\.js\.download$/.js/' '{}' +
17. Copy folder structure including only files of a specific extension into an ouput Folder
find . -name '*.md' | cpio -pdm './../outputFolder'
- Common Bash Use Cases
- Table of Contents
- STRINGS
- Trim leading and trailing white-space from string
- Trim all white-space from string and truncate spaces
- Use regex on a string
- Split a string on a delimiter
- Change a string to lowercase
- Change a string to uppercase
- Reverse a string case
- Trim quotes from a string
- Strip all instances of pattern from string
- Strip first occurrence of pattern from string
- Strip pattern from start of string
- Strip pattern from end of string
- Percent-encode a string
- Decode a percent-encoded string
- Check if string contains a sub-string
- Check if string starts with sub-string
- Check if string ends with sub-string
- ARRAYS
- LOOPS
- FILE HANDLING
- FILE PATHS
- VARIABLES
- ESCAPE SEQUENCES
- PARAMETER EXPANSION
- BRACE EXPANSION
- CONDITIONAL EXPRESSIONS
- ARITHMETIC OPERATORS
- ARITHMETIC
- TRAPS
- PERFORMANCE
- OBSOLETE SYNTAX
- INTERNAL VARIABLES
- Get the location to the
bash
binary - Get the version of the current running
bash
process - Open the user's preferred text editor
- Get the name of the current function
- Get the host-name of the system
- Get the architecture of the Operating System
- Get the name of the Operating System / Kernel
- Get the current working directory
- Get the number of seconds the script has been running
- Get a pseudorandom integer
- Get the location to the
- INFORMATION ABOUT THE TERMINAL
- CONVERSION
- CODE GOLF
- OTHER
- Use
read
as an alternative to thesleep
command - Check if a program is in the user's PATH
- Get the current date using
strftime
- Get the username of the current user
- Generate a UUID V4
- Progress bars
- Get the list of functions in a script
- Bypass shell aliases
- Bypass shell functions
- Run a command in the background
- Capture the return value of a function without command substitution
- Use
- AFTERWORD
This is an alternative to sed
, awk
, perl
and other tools. The
function below works by finding all leading and trailing white-space and
removing it from the start and end of the string. The :
built-in is used in place of a temporary variable.
Example Function:
trim_string() {
# Usage: trim_string " example string "
: "${1#"${1%%[![:space:]]*}"}"
: "${_%"${_
---
## *[![:space:]]}"}"
printf '%s\n' "$_"
}
Example Usage:
$ trim_string " Hello, World "
Hello, World
$ name=" John Black "
$ trim_string "$name"
John Black
This is an alternative to sed
, awk
, perl
and other tools. The
function below works by abusing word splitting to create a new string
without leading/trailing white-space and with truncated spaces.
Example Function:
# shellcheck disable=SC2086,SC2048
trim_all() {
# Usage: trim_all " example string "
set -f
set -- $*
printf '%s\n' "$*"
set +f
}
Example Usage:
$ trim_all " Hello, World "
Hello, World
$ name=" John Black is my name. "
$ trim_all "$name"
John Black is my name.
The result of bash
's regex matching can be used to replace sed
for a
large number of use-cases.
CAVEAT: This is one of the few platform dependent bash
features.
bash
will use whatever regex engine is installed on the user's system.
Stick to POSIX regex features if aiming for compatibility.
CAVEAT: This example only prints the first matching group. When using multiple capture groups some modification is needed.
Example Function:
regex() {
# Usage: regex "string" "regex"
[[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}"
}
Example Usage:
$ # Trim leading white-space.
$ regex ' hello' '^\s*(.*)'
hello
$ # Validate a hex color.
$ regex "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
#FFFFFF
$ # Validate a hex color (invalid).
$ regex "red" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
# no output (invalid)
Example Usage in script:
is_hex_color() {
if [[ $1 =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then
printf '%s\n' "${BASH_REMATCH[1]}"
else
printf '%s\n' "error: $1 is an invalid color."
return 1
fi
}
read -r color
is_hex_color "$color" || color="#FFFFFF"
# Do stuff.
CAVEAT: Requires bash
4+
This is an alternative to cut
, awk
and other tools.
Example Function:
split() {
# Usage: split "string" "delimiter"
IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}"
printf '%s\n' "${arr[@]}"
}
Example Usage:
$ split "apples,oranges,pears,grapes" ","
apples
oranges
pears
grapes
$ split "1, 2, 3, 4, 5" ", "
1
2
3
4
5
# Multi char delimiters work too!
$ split "hello---world---my---name---is---john" "---"
hello
world
my
name
is
john
CAVEAT: Requires bash
4+
Example Function:
lower() {
# Usage: lower "string"
printf '%s\n' "${1,,}"
}
Example Usage:
$ lower "HELLO"
hello
$ lower "HeLlO"
hello
$ lower "hello"
hello
CAVEAT: Requires bash
4+
Example Function:
upper() {
# Usage: upper "string"
printf '%s\n' "${1^^}"
}
Example Usage:
$ upper "hello"
HELLO
$ upper "HeLlO"
HELLO
$ upper "HELLO"
HELLO
CAVEAT: Requires bash
4+
Example Function:
reverse_case() {
# Usage: reverse_case "string"
printf '%s\n' "${1~~}"
}
Example Usage:
$ reverse_case "hello"
HELLO
$ reverse_case "HeLlO"
hElLo
$ reverse_case "HELLO"
hello
Example Function:
trim_quotes() {
# Usage: trim_quotes "string"
: "${1//\'}"
printf '%s\n' "${_//\"}"
}
Example Usage:
$ var="'Hello', \"World\""
$ trim_quotes "$var"
Hello, World
Example Function:
strip_all() {
# Usage: strip_all "string" "pattern"
printf '%s\n' "${1//$2}"
}
Example Usage:
$ strip_all "The Quick Brown Fox" "[aeiou]"
Th Qck Brwn Fx
$ strip_all "The Quick Brown Fox" "[[:space:]]"
TheQuickBrownFox
$ strip_all "The Quick Brown Fox" "Quick "
The Brown Fox
Example Function:
strip() {
# Usage: strip "string" "pattern"
printf '%s\n' "${1/$2}"
}
Example Usage:
$ strip "The Quick Brown Fox" "[aeiou]"
Th Quick Brown Fox
$ strip "The Quick Brown Fox" "[[:space:]]"
TheQuick Brown Fox
Example Function:
lstrip() {
# Usage: lstrip "string" "pattern"
printf '%s\n' "${1
---
## $2}"
}
Example Usage:
$ lstrip "The Quick Brown Fox" "The "
Quick Brown Fox
Example Function:
rstrip() {
# Usage: rstrip "string" "pattern"
printf '%s\n' "${1%%$2}"
}
Example Usage:
$ rstrip "The Quick Brown Fox" " Fox"
The Quick Brown
Example Function:
urlencode() {
# Usage: urlencode "string"
local LC_ALL=C
for (( i = 0; i < ${#1}; i++ )); do
: "${1:i:1}"
case "$_" in
[a-zA-Z0-9.~_-])
printf '%s' "$_"
;;
*)
printf '%%%02X' "'$_"
;;
esac
done
printf '\n'
}
Example Usage:
$ urlencode "https://github.com/dylanaraps/pure-bash-bible"
https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible
Example Function:
urldecode() {
# Usage: urldecode "string"
: "${1//+/ }"
printf '%b\n' "${_//%/\\x}"
}
Example Usage:
$ urldecode "https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible"
https://github.com/dylanaraps/pure-bash-bible
Using a test:
if [[ $var == *sub_string* ]]; then
printf '%s\n' "sub_string is in var."
fi
# Inverse (substring not in string).
if [[ $var != *sub_string* ]]; then
printf '%s\n' "sub_string is not in var."
fi
# This works for arrays too!
if [[ ${arr[*]} == *sub_string* ]]; then
printf '%s\n' "sub_string is in array."
fi
Using a case statement:
case "$var" in
*sub_string*)
# Do stuff
;;
*sub_string2*)
# Do more stuff
;;
*)
# Else
;;
esac
if [[ $var == sub_string* ]]; then
printf '%s\n' "var starts with sub_string."
fi
# Inverse (var does not start with sub_string).
if [[ $var != sub_string* ]]; then
printf '%s\n' "var does not start with sub_string."
fi
if [[ $var == *sub_string ]]; then
printf '%s\n' "var ends with sub_string."
fi
# Inverse (var does not end with sub_string).
if [[ $var != *sub_string ]]; then
printf '%s\n' "var does not end with sub_string."
fi
Enabling extdebug
allows access to the BASH_ARGV
array which stores
the current function’s arguments in reverse.
CAVEAT: Requires shopt -s compat44
in bash
5.0+.
Example Function:
reverse_array() {
# Usage: reverse_array "array"
shopt -s extdebug
f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
shopt -u extdebug
}
Example Usage:
$ reverse_array 1 2 3 4 5
5
4
3
2
1
$ arr=(red blue green)
$ reverse_array "${arr[@]}"
green
blue
red
Create a temporary associative array. When setting associative array values and a duplicate assignment occurs, bash overwrites the key. This allows us to effectively remove array duplicates.
CAVEAT: Requires bash
4+
CAVEAT: List order may not stay the same.
Example Function:
remove_array_dups() {
# Usage: remove_array_dups "array"
declare -A tmp_array
for i in "$@"; do
[[ $i ]] && IFS=" " tmp_array["${i:- }"]=1
done
printf '%s\n' "${!tmp_array[@]}"
}
Example Usage:
$ remove_array_dups 1 1 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 5
1
2
3
4
5
$ arr=(red red green blue blue)
$ remove_array_dups "${arr[@]}"
red
green
blue
Example Function:
random_array_element() {
# Usage: random_array_element "array"
local arr=("$@")
printf '%s\n' "${arr[RANDOM % $#]}"
}
Example Usage:
$ array=(red green blue yellow brown)
$ random_array_element "${array[@]}"
yellow
# Multiple arguments can also be passed.
$ random_array_element 1 2 3 4 5 6 7
3
Each time the printf
is called, the next array element is printed. When
the print hits the last array element it starts from the first element
again.
arr=(a b c d)
cycle() {
printf '%s ' "${arr[${i:=0}]}"
((i=i>=${#arr[@]}-1?0:++i))
}
This works the same as above, this is just a different use case.
arr=(true false)
cycle() {
printf '%s ' "${arr[${i:=0}]}"
((i=i>=${#arr[@]}-1?0:++i))
}
Alternative to seq
.
# Loop from 0-100 (no variable support).
for i in {0..100}; do
printf '%s\n' "$i"
done
Alternative to seq
.
# Loop from 0-VAR.
VAR=50
for ((i=0;i<=VAR;i++)); do
printf '%s\n' "$i"
done
arr=(apples oranges tomatoes)
# Just elements.
for element in "${arr[@]}"; do
printf '%s\n' "$element"
done
arr=(apples oranges tomatoes)
# Elements and index.
for i in "${!arr[@]}"; do
printf '%s\n' "${arr[i]}"
done
# Alternative method.
for ((i=0;i<${#arr[@]};i++)); do
printf '%s\n' "${arr[i]}"
done
while read -r line; do
printf '%s\n' "$line"
done < "file"
Don’t use ls
.
# Greedy example.
for file in *; do
printf '%s\n' "$file"
done
# PNG files in dir.
for file in ~/Pictures/*.png; do
printf '%s\n' "$file"
done
# Iterate over directories.
for dir in ~/Downloads/*/; do
printf '%s\n' "$dir"
done
# Brace Expansion.
for file in /path/to/parentdir/{file1,file2,subdir/file3}; do
printf '%s\n' "$file"
done
# Iterate recursively.
shopt -s globstar
for file in ~/Pictures/**/*; do
printf '%s\n' "$file"
done
shopt -u globstar
CAVEAT: bash
does not handle binary data properly in versions < 4.4
.
Alternative to the cat
command.
file_data="$(<"file")"
Alternative to the cat
command.
# Bash <4 (discarding empty lines).
IFS=$'\n' read -d "" -ra file_data < "file"
# Bash <4 (preserving empty lines).
while read -r line; do
file_data+=("$line")
done < "file"
# Bash 4+
mapfile -t file_data < "file"
Alternative to the head
command.
CAVEAT: Requires bash
4+
Example Function:
head() {
# Usage: head "n" "file"
mapfile -tn "$1" line < "$2"
printf '%s\n' "${line[@]}"
}
Example Usage:
$ head 2 ~/.bashrc
# Prompt
PS1='➜ '
$ head 1 ~/.bashrc
# Prompt
Alternative to the tail
command.
CAVEAT: Requires bash
4+
Example Function:
tail() {
# Usage: tail "n" "file"
mapfile -tn 0 line < "$2"
printf '%s\n' "${line[@]: -$1}"
}
Example Usage:
$ tail 2 ~/.bashrc
# Enable tmux.
# [[ -z "$TMUX" ]] && exec tmux
$ tail 1 ~/.bashrc
# [[ -z "$TMUX" ]] && exec tmux
Alternative to wc -l
.
Example Function (bash 4):
lines() {
# Usage: lines "file"
mapfile -tn 0 lines < "$1"
printf '%s\n' "${#lines[@]}"
}
Example Function (bash 3):
This method uses less memory than the mapfile
method and works in bash
3 but it is slower for bigger files.
lines_loop() {
# Usage: lines_loop "file"
count=0
while IFS= read -r _; do
((count++))
done < "$1"
printf '%s\n' "$count"
}
Example Usage:
$ lines ~/.bashrc
48
$ lines_loop ~/.bashrc
48
This works by passing the output of the glob to the function and then counting the number of arguments.
Example Function:
count() {
# Usage: count /path/to/dir/*
# count /path/to/dir/*/
printf '%s\n' "$#"
}
Example Usage:
# Count all files in dir.
$ count ~/Downloads/*
232
# Count all dirs in dir.
$ count ~/Downloads/*/
45
# Count all jpg files in dir.
$ count ~/Pictures/*.jpg
64
Alternative to touch
.
# Shortest.
>file
# Longer alternatives:
:>file
echo -n >file
printf '' >file
Example Function:
extract() {
# Usage: extract file "opening marker" "closing marker"
while IFS=$'\n' read -r line; do
[[ $extract && $line != "$3" ]] &&
printf '%s\n' "$line"
[[ $line == "$2" ]] && extract=1
[[ $line == "$3" ]] && extract=
done < "$1"
}
Example Usage:
# Extract code blocks from MarkDown file.
$ extract ~/projects/pure-bash/README.md '```sh' '```'
# Output here...
Alternative to the dirname
command.
Example Function:
dirname() {
# Usage: dirname "path"
local tmp=${1:-.}
[[ $tmp != *[!/]* ]] && {
printf '/\n'
return
}
tmp=${tmp%%"${tmp
---
## *[!/]}"}
[[ $tmp != */* ]] && {
printf '.\n'
return
}
tmp=${tmp%/*}
tmp=${tmp%%"${tmp
---
## *[!/]}"}
printf '%s\n' "${tmp:-/}"
}
Example Usage:
$ dirname ~/Pictures/Wallpapers/1.jpg
/home/black/Pictures/Wallpapers
$ dirname ~/Pictures/Downloads/
/home/black/Pictures
Alternative to the basename
command.
Example Function:
basename() {
# Usage: basename "path" ["suffix"]
local tmp
tmp=${1%"${1
---
## *[!/]}"}
tmp=${tmp
---
## */}
tmp=${tmp%"${2/"$tmp"}"}
printf '%s\n' "${tmp:-/}"
}
Example Usage:
$ basename ~/Pictures/Wallpapers/1.jpg
1.jpg
$ basename ~/Pictures/Wallpapers/1.jpg .jpg
1
$ basename ~/Pictures/Downloads/
Downloads
$ hello_world="value"
# Create the variable name.
$ var="world"
$ ref="hello_$var"
# Print the value of the variable name stored in 'hello_$var'.
$ printf '%s\n' "${!ref}"
value
Alternatively, on bash
4.3+:
$ hello_world="value"
$ var="world"
# Declare a nameref.
$ declare -n ref=hello_$var
$ printf '%s\n' "$ref"
value
$ var="world"
$ declare "hello_$var=value"
$ printf '%s\n' "$hello_world"
value
Contrary to popular belief, there is no issue in utilizing raw escape sequences. Using tput
abstracts the same ANSI sequences as if printed manually. Worse still, tput
is not actually portable. There are a number of tput
variants each with different commands and syntaxes (try tput setaf 3
on a FreeBSD system). Raw sequences are fine.
NOTE: Sequences requiring RGB values only work in True-Color Terminal Emulators.
Sequence | What does it do? | Value |
---|---|---|
\e[38;5;<NUM>m |
Set text foreground color. | 0-255 |
\e[48;5;<NUM>m |
Set text background color. | 0-255 |
\e[38;2;<R>;<G>;<B>m |
Set text foreground color to RGB color. | R , G , B |
\e[48;2;<R>;<G>;<B>m |
Set text background color to RGB color. | R , G , B |
NOTE: Prepend 2 to any code below to turn it's effect off (examples: 21=bold text off, 22=faint text off, 23=italic text off).
Sequence | What does it do? |
---|---|
\e[m |
Reset text formatting and colors. |
\e[1m |
Bold text. |
\e[2m |
Faint text. |
\e[3m |
Italic text. |
\e[4m |
Underline text. |
\e[5m |
Blinking text. |
\e[7m |
Highlighted text. |
\e[8m |
Hidden text. |
\e[9m |
Strike-through text. |
Sequence | What does it do? | Value |
---|---|---|
\e[<LINE>;<COLUMN>H |
Move cursor to absolute position. | line , column |
\e[H |
Move cursor to home position (0,0 ). |
|
\e[<NUM>A |
Move cursor up N lines. | num |
\e[<NUM>B |
Move cursor down N lines. | num |
\e[<NUM>C |
Move cursor right N columns. | num |
\e[<NUM>D |
Move cursor left N columns. | num |
\e[s |
Save cursor position. | |
\e[u |
Restore cursor position. |
Sequence | What does it do? |
---|---|
\e[K |
Erase from cursor position to end of line. |
\e[1K |
Erase from cursor position to start of line. |
\e[2K |
Erase the entire current line. |
\e[J |
Erase from the current line to the bottom of the screen. |
\e[1J |
Erase from the current line to the top of the screen. |
\e[2J |
Clear the screen. |
\e[2J\e[H |
Clear the screen and move cursor to 0,0 . |
Parameter | What does it do? |
---|---|
${!VAR} |
Access a variable based on the value of VAR . |
${!VAR*} |
Expand to IFS separated list of variable names starting with VAR . |
${!VAR@} |
Expand to IFS separated list of variable names starting with VAR . If double-quoted, each variable name expands to a separate word. |
Parameter | What does it do? |
---|---|
${VAR#PATTERN} |
Remove shortest match of pattern from start of string. |
`${VAR |
| ${VAR%PATTERN}
| Remove shortest match of pattern from end of string. |
| ${VAR%%PATTERN}
| Remove longest match of pattern from end of string. |
| ${VAR/PATTERN/REPLACE}
| Replace first match with string.
| ${VAR//PATTERN/REPLACE}
| Replace all matches with string.
| ${VAR/PATTERN}
| Remove first match.
| ${VAR//PATTERN}
| Remove all matches.
Parameter | What does it do? |
---|---|
${#VAR} |
Length of var in characters. |
${#ARR[@]} |
Length of array in elements. |
Parameter | What does it do? |
---|---|
${VAR:OFFSET} |
Remove first N chars from variable. |
${VAR:OFFSET:LENGTH} |
Get substring from N character to N character. ( ${VAR:10:10} : Get sub-string from char 10 to char 20 ) |
${VAR:: OFFSET} |
Get first N chars from variable. |
${VAR:: -OFFSET} |
Remove last N chars from variable. |
${VAR: -OFFSET} |
Get last N chars from variable. |
${VAR:OFFSET:-OFFSET} |
Cut first N chars and last N chars. |
Parameter | What does it do? | CAVEAT |
---|---|---|
${VAR^} |
Uppercase first character. | bash 4+ |
${VAR^^} |
Uppercase all characters. | bash 4+ |
${VAR,} |
Lowercase first character. | bash 4+ |
${VAR,,} |
Lowercase all characters. | bash 4+ |
${VAR~} |
Reverse case of first character. | bash 4+ |
${VAR~~} |
Reverse case of all characters. | bash 4+ |
Parameter | What does it do? |
---|---|
${VAR:-STRING} |
If VAR is empty or unset, use STRING as its value. |
${VAR-STRING} |
If VAR is unset, use STRING as its value. |
${VAR:=STRING} |
If VAR is empty or unset, set the value of VAR to STRING . |
${VAR=STRING} |
If VAR is unset, set the value of VAR to STRING . |
${VAR:+STRING} |
If VAR is not empty, use STRING as its value. |
${VAR+STRING} |
If VAR is set, use STRING as its value. |
${VAR:?STRING} |
Display an error if empty or unset. |
${VAR?STRING} |
Display an error if unset. |
# Syntax: {<START>..<END>}
# Print numbers 1-100.
echo {1..100}
# Print range of floats.
echo 1.{1..9}
# Print chars a-z.
echo {a..z}
echo {A..Z}
# Nesting.
echo {A..Z}{0..9}
# Print zero-padded numbers.
# CAVEAT: bash 4+
echo {01..100}
# Change increment amount.
# Syntax: {<START>..<END>..<INCREMENT>}
# CAVEAT: bash 4+
echo {1..10..2} # Increment by 2.
echo {apples,oranges,pears,grapes}
# Example Usage:
# Remove dirs Movies, Music and ISOS from ~/Downloads/.
rm -rf ~/Downloads/{Movies,Music,ISOS}
Expression | Value | What does it do? |
---|---|---|
-a |
file |
If file exists. |
-b |
file |
If file exists and is a block special file. |
-c |
file |
If file exists and is a character special file. |
-d |
file |
If file exists and is a directory. |
-e |
file |
If file exists. |
-f |
file |
If file exists and is a regular file. |
-g |
file |
If file exists and its set-group-id bit is set. |
-h |
file |
If file exists and is a symbolic link. |
-k |
file |
If file exists and its sticky-bit is set |
-p |
file |
If file exists and is a named pipe (FIFO). |
-r |
file |
If file exists and is readable. |
-s |
file |
If file exists and its size is greater than zero. |
-t |
fd |
If file descriptor is open and refers to a terminal. |
-u |
file |
If file exists and its set-user-id bit is set. |
-w |
file |
If file exists and is writable. |
-x |
file |
If file exists and is executable. |
-G |
file |
If file exists and is owned by the effective group ID. |
-L |
file |
If file exists and is a symbolic link. |
-N |
file |
If file exists and has been modified since last read. |
-O |
file |
If file exists and is owned by the effective user ID. |
-S |
file |
If file exists and is a socket. |
Expression | What does it do? |
---|---|
file -ef file2 |
If both files refer to the same inode and device numbers. |
file -nt file2 |
If file is newer than file2 (uses modification time) or file exists and file2 does not. |
file -ot file2 |
If file is older than file2 (uses modification time) or file2 exists and file does not. |
Expression | Value | What does it do? |
---|---|---|
-o |
opt |
If shell option is enabled. |
-v |
var |
If variable has a value assigned. |
-R |
var |
If variable is a name reference. |
-z |
var |
If the length of string is zero. |
-n |
var |
If the length of string is non-zero. |
Expression | What does it do? |
---|---|
var = var2 |
Equal to. |
var == var2 |
Equal to (synonym for = ). |
var != var2 |
Not equal to. |
var < var2 |
Less than (in ASCII alphabetical order.) |
var > var2 |
Greater than (in ASCII alphabetical order.) |
Operators | What does it do? |
---|---|
= |
Initialize or change the value of a variable. |
Operators | What does it do? |
---|---|
+ |
Addition |
- |
Subtraction |
* |
Multiplication |
/ |
Division |
** |
Exponentiation |
% |
Modulo |
+= |
Plus-Equal (Increment a variable.) |
-= |
Minus-Equal (Decrement a variable.) |
*= |
Times-Equal (Multiply a variable.) |
/= |
Slash-Equal (Divide a variable.) |
%= |
Mod-Equal (Remainder of dividing a variable.) |
Operators | What does it do? |
---|---|
<< |
Bitwise Left Shift |
<<= |
Left-Shift-Equal |
>> |
Bitwise Right Shift |
>>= |
Right-Shift-Equal |
& |
Bitwise AND |
&= |
Bitwise AND-Equal |
| |
Bitwise OR |
|= |
Bitwise OR-Equal |
~ |
Bitwise NOT |
^ |
Bitwise XOR |
^= |
Bitwise XOR-Equal |
Operators | What does it do? |
---|---|
! |
NOT |
&& |
AND |
|| |
OR |
Operators | What does it do? | Example |
---|---|---|
, |
Comma Separator | ((a=1,b=2,c=3)) |
# Simple math
((var=1+2))
# Decrement/Increment variable
((var++))
((var--))
((var+=1))
((var-=1))
# Using variables
((var=var2*arr[2]))
# Set the value of var to var2 if var2 is greater than var.
# var: variable to set.
# var2>var: Condition to test.
# ?var2: If the test succeeds.
# :var: If the test fails.
((var=var2>var?var2:var))
Traps allow a script to execute code on various signals. In pxltrm (a pixel art editor written in bash) traps are used to redraw the user interface on window resize. Another use case is cleaning up temporary files on script exit.
Traps should be added near the start of scripts so any early errors are also caught.
NOTE: For a full list of signals, see trap -l
.
# Clear screen on script exit.
trap 'printf \\e[2J\\e[H\\e[m' EXIT
trap '' INT
# Call a function on window resize.
trap 'code_here' SIGWINCH
trap 'code_here' DEBUG
trap 'code_here' RETURN
If unicode is not required, it can be disabled for a performance increase. Results may vary however there have been noticeable improvements in neofetch and other programs.
# Disable unicode.
LC_ALL=C
LANG=C
Use #!/usr/bin/env bash
instead of #!/bin/bash
.
- The former searches the user's
PATH
to find thebash
binary. - The latter assumes it is always installed to
/bin/
which can cause issues.
NOTE: There are times when one may have a good reason for using #!/bin/bash
or another direct path to the binary.
# Right:
#!/usr/bin/env bash
# Less right:
#!/bin/bash
Use $()
instead of ` `
.
# Right.
var="$(command)"
# Wrong.
var=`command`
# $() can easily be nested whereas `` cannot.
var="$(command "$(command)")"
Do not use the function
keyword, it reduces compatibility with older versions of bash
.
# Right.
do_something() {
# ...
}
# Wrong.
function do_something() {
# ...
}
"$BASH"
# As a string.
"$BASH_VERSION"
# As an array.
"${BASH_VERSINFO[@]}"
"$EDITOR" "$file"
# NOTE: This variable may be empty, set a fallback value.
"${EDITOR:-vi}" "$file"
# Current function.
"${FUNCNAME[0]}"
# Parent function.
"${FUNCNAME[1]}"
# So on and so forth.
"${FUNCNAME[2]}"
"${FUNCNAME[3]}"
# All functions including parents.
"${FUNCNAME[@]}"
"$HOSTNAME"
# NOTE: This variable may be empty.
# Optionally set a fallback to the hostname command.
"${HOSTNAME:-$(hostname)}"
"$HOSTTYPE"
This can be used to add conditional support for different Operating
Systems without needing to call uname
.
"$OSTYPE"
This is an alternative to the pwd
built-in.
"$PWD"
"$SECONDS"
Each time $RANDOM
is used, a different integer between 0
and 32767
is returned. This variable should not be used for anything related to security (this includes encryption keys etc).
"$RANDOM"
This is handy when writing scripts in pure bash and stty
/tput
can’t be
called.
Example Function:
get_term_size() {
# Usage: get_term_size
# (:;:) is a micro sleep to ensure the variables are
# exported immediately.
shopt -s checkwinsize; (:;:)
printf '%s\n' "$LINES $COLUMNS"
}
Example Usage:
# Output: LINES COLUMNS
$ get_term_size
15 55
CAVEAT: This does not work in some terminal emulators.
Example Function:
get_window_size() {
# Usage: get_window_size
printf '%b' "${TMUX:+\\ePtmux;\\e}\\e[14t${TMUX:+\\e\\\\}"
IFS=';t' read -d t -t 0.05 -sra term_size
printf '%s\n' "${term_size[1]}x${term_size[2]}"
}
Example Usage:
# Output: WIDTHxHEIGHT
$ get_window_size
1200x800
# Output (fail):
$ get_window_size
x
This is useful when creating a TUI in pure bash.
Example Function:
get_cursor_pos() {
# Usage: get_cursor_pos
IFS='[;' read -p $'\e[6n' -d R -rs _ y x _
printf '%s\n' "$x $y"
}
Example Usage:
# Output: X Y
$ get_cursor_pos
1 8
Example Function:
hex_to_rgb() {
# Usage: hex_to_rgb "#FFFFFF"
# hex_to_rgb "000000"
: "${1/\#}"
((r=16#${_:0:2},g=16#${_:2:2},b=16#${_:4:2}))
printf '%s\n' "$r $g $b"
}
Example Usage:
$ hex_to_rgb "#FFFFFF"
255 255 255
Example Function:
rgb_to_hex() {
# Usage: rgb_to_hex "r" "g" "b"
printf '#%02x%02x%02x\n' "$1" "$2" "$3"
}
Example Usage:
$ rgb_to_hex "255" "255" "255"
#FFFFFF
# Tiny C Style.
for((;i++<10;)){ echo "$i";}
# Undocumented method.
for i in {1..10};{ echo "$i";}
# Expansion.
for i in {1..10}; do echo "$i"; done
# C Style.
for((i=0;i<=10;i++)); do echo "$i"; done
# Normal method
while :; do echo hi; done
# Shorter
for((;;)){ echo hi;}
# Normal method
f(){ echo hi;}
# Using a subshell
f()(echo hi)
# Using arithmetic
# This can be used to assign integer values.
# Example: f a=1
# f a++
f()(($1))
# Using tests, loops etc.
# NOTE: ‘while’, ‘until’, ‘case’, ‘(())’, ‘[[]]’ can also be used.
f()if true; then echo "$1"; fi
f()for i in "$@"; do echo "$i"; done
# One line
# Note: The 3rd statement may run when the 1st is true
[[ $var == hello ]] && echo hi || echo bye
[[ $var == hello ]] && { echo hi; echo there; } || echo bye
# Multi line (no else, single statement)
# Note: The exit status may not be the same as with an if statement
[[ $var == hello ]] &&
echo hi
# Multi line (no else)
[[ $var == hello ]] && {
echo hi
# ...
}
The :
built-in can be used to avoid repeating variable=
in a case statement. The $_
variable stores the last argument of the last command. :
always succeeds so it can be used to store the variable value.
# Modified snippet from Neofetch.
case "$OSTYPE" in
"darwin"*)
: "MacOS"
;;
"linux"*)
: "Linux"
;;
*"bsd"* | "dragonfly" | "bitrig")
: "BSD"
;;
"cygwin" | "msys" | "win32")
: "Windows"
;;
*)
printf '%s\n' "Unknown OS detected, aborting..." >&2
exit 1
;;
esac
# Finally, set the variable.
os="$_"
Surprisingly, sleep
is an external command and not a bash
built-in.
CAVEAT: Requires bash
4+
Example Function:
read_sleep() {
# Usage: read_sleep 1
# read_sleep 0.2
read -rt "$1" <> <(:) || :
}
Example Usage:
read_sleep 1
read_sleep 0.1
read_sleep 30
For performance-critical situations, where it is not economic to open and close an excessive number of file descriptors, the allocation of a file descriptor may be done only once for all invocations of read
:
(See the generic original implementation at https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever)
exec {sleep_fd}<> <(:)
while some_quick_test; do
# equivalent of sleep 0.001
read -t 0.001 -u $sleep_fd
done
# There are 3 ways to do this and either one can be used.
type -p executable_name &>/dev/null
hash executable_name &>/dev/null
command -v executable_name &>/dev/null
# As a test.
if type -p executable_name &>/dev/null; then
# Program is in PATH.
fi
# Inverse.
if ! type -p executable_name &>/dev/null; then
# Program is not in PATH.
fi
# Example (Exit early if program is not installed).
if ! type -p convert &>/dev/null; then
printf '%s\n' "error: convert is not installed, exiting..."
exit 1
fi
Bash’s printf
has a built-in method of getting the date which can be used in place of the date
command.
CAVEAT: Requires bash
4+
Example Function:
date() {
# Usage: date "format"
# See: 'man strftime' for format.
printf "%($1)T\\n" "-1"
}
Example Usage:
# Using above function.
$ date "%a %d %b - %l:%M %p"
Fri 15 Jun - 10:00 AM
# Using printf directly.
$ printf '%(%a %d %b - %l:%M %p)T\n' "-1"
Fri 15 Jun - 10:00 AM
# Assigning a variable using printf.
$ printf -v date '%(%a %d %b - %l:%M %p)T\n' '-1'
$ printf '%s\n' "$date"
Fri 15 Jun - 10:00 AM
CAVEAT: Requires bash
4.4+
$ : \\u
# Expand the parameter as if it were a prompt string.
$ printf '%s\n' "${_@P}"
black
CAVEAT: The generated value is not cryptographically secure.
Example Function:
uuid() {
# Usage: uuid
C="89ab"
for ((N=0;N<16;++N)); do
B="$((RANDOM%256))"
case "$N" in
6) printf '4%x' "$((B%16))" ;;
8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;;
3|5|7|9)
printf '%02x-' "$B"
;;
*)
printf '%02x' "$B"
;;
esac
done
printf '\n'
}
Example Usage:
$ uuid
d5b6c731-1310-4c24-9fe3-55d556d44374
This is a simple way of drawing progress bars without needing a for loop in the function itself.
Example Function:
bar() {
# Usage: bar 1 10
# ^----- Elapsed Percentage (0-100).
# ^-- Total length in chars.
((elapsed=$1*$2/100))
# Create the bar with spaces.
printf -v prog "%${elapsed}s"
printf -v total "%$(($2-elapsed))s"
printf '%s\r' "[${prog// /-}${total}]"
}
Example Usage:
for ((i=0;i<=100;i++)); do
# Pure bash micro sleeps (for the example).
(:;:) && (:;:) && (:;:) && (:;:) && (:;:)
# Print the bar.
bar "$i" "10"
done
printf '\n'
get_functions() {
# Usage: get_functions
IFS=$'\n' read -d "" -ra functions < <(declare -F)
printf '%s\n' "${functions[@]//declare -f }"
}
# alias
ls
# command
# shellcheck disable=SC1001
\ls
# function
ls
# command
command ls
This will run the given command and keep it running, even after the terminal or SSH connection is terminated. All output is ignored.
bkr() {
(nohup "$@" &>/dev/null &)
}
bkr ./some_script.sh # some_script.sh is now running in the background
CAVEAT: Requires bash
4+
This uses local namerefs to avoid using var=$(some_func)
style command substitution for function output capture.
to_upper() {
local -n ptr=${1}
ptr=${ptr^^}
}
foo="bar"
to_upper foo
printf "%s\n" "${foo}" # BAR