Skip to content

3.1 Bash scripting

Brace Expansion
❯ echo {1..5}
1 2 3 4 5
❯ echo {0..20..2}
0 2 4 6 8 10 12 14 16 18 20
❯ echo {a..f}
a b c d e f

❯ touch file{1..4}.txt
❯ ls
file1.txt  file2.txt  file3.txt  file4.txt 

❯ cp -p file.config{,.bak}
❯ ls
file.config  file.config.bak

❯ echo {contents,paper,bilbiography}.md
contents.md  paper.md  bilbiography.md

❯ wget https://www.some-url.com/picture{1..8}.jpg
Command Substitution

Capture the output of a command, and store it in a variable.

var=$(command)

or

var=`command`
my_date=`date +%m-%d-%Y`
#OR
my_date=$(date +%m-%d-%Y)
echo "You accessed this date on $my_date"

Output

You accessed this date on 09-13-2023
Globbing

Globbing in Bash refers to how the shell interprets special characters such as *, and ? which are commonly used to match filenames. Bash itself cannot recognize regular expressions, instead we use tools like sed and awk. It is important to distinguish globbing and regex as they can be easily confused.

The question mark matches any single character while the asterisks matches zero or more characters.

❯ ls file?.txt
file1.txt  file2.txt  file3.txt file4.txt file5.txt

❯ ls file[1-3].txt
file1.txt  file2.txt  file3.txt

❯ ls *.txt
dep.txt  file1.txt  file2.txt  file3.txt  file4.txt file5.txt   marks.txt

❯ ls file?+(.png|.txt)
file1.png  file1.txt  file2.png  file2.txt  file3.png  file3.txt  file4.png  file5.png
Here Documents

Send multiple lines of text to a command or shell script.

command << [marker]
input
[marker]
❯ sort << END
∙ 3
∙ 2
∙ 4
∙ 1
∙ END
1
2
3
4
Here String

Send one line of text to a command or shell script.

❯ wc -c <<< "String with many characters"
28

❯ foo="bar"
❯ sed 's/a/A/' <<< "$foo"
 bAr
Shell control and redirection

>&, &>, >>& and &>> : (read above also) Redirect both standard error and standard output, replacing or appending, respectively.

Additional

source reads and executes the contents of a file as sets of commands in the current shell.

Here is a file called commands.txt

echo "Your current directory is `pwd`"
echo "The date is `date +%m-%d`"
❯ source commands.txt
Your current directory is /home/promptier/Desktop/bash
The date is 11-20

Note source script is equivalent to . script, not to be confused with ./script, which runs the script as an executable file, launching a new shell to run it.

The type command is useful to learn more about a command. If it is a shell built in, it will not have a man page, instead, read about it using man bash.

❯ man source
No manual entry for source

❯ type source
source is a shell builtin

The $PATH variable contains a list of directories the system checks before running a command. Instead of running /usr/bin/python3, we can just run python3 because /usr/bin is located in the path.

If you install a program that is not located in the $PATH variable, you can add it with either of the following two ways:

export PATH=/the/file/path:$PATH $
#adds to the beginnning and will be checked first
#OR
export PATH=$PATH:/the/file/path
#adds to the end and will be checked last
Script Utilities

By default, tee will overwrite files, use -a to append:

command | tee -a file

Tee can also be useful when writing to a protected file.

echo "newline" | sudo tee -a secret.txt

It is called "tee" as it resembles the letter "T" as well as the T-splitter in plumming since it takes from STDIN and "splits" or writes to both STDOUT and files.

egrep, fgrep and rgrep are the same as grep -E, grep -F, and grep -r.

grep -F is a fixed string, meaning you want the string to be passed verbatim, and not interpreted as special regex. Such as if the search includes a dot user.txt that you don't want to be interpreted as a regex wildcard.

grep -E is extended grep, which can be used for fancy expressions, like () for groups and | for OR. Here we search for any line that starts with "fork" or "group".

❯ grep -E '^no(fork|group)' /etc/group
nogroup:x:65534:

If you used regular grep without the -E, you'd have to escape out the special characters or else they'd be searched literally.

grep '^no\(fork\|group\)' /etc/group

As another useful example, we search for PCI devices starting with either "ethernet" or "network" with an insensitive search.

❯ lspci | egrep -i 'ethernet|network'
00:19.0 Ethernet controller: Intel Corporation 82579LM Gigabit Network Connection (Lewisville) (rev 04)
03:00.0 Network controller: Intel Corporation Centrino Advanced-N 6205 [Taylor Peak] (rev 34)