Linux BASH Programming Cookbook
Linux BASH Programming Cookbook
Contents
Preface
Bash is a Unix shell and command language written by Brian Fox for the GNU Project as a free software replacement for the
Bourne shell. First released in 1989, it has been distributed widely as it is a default shell on the major Linux distributions and OS
X.
Bash is a command processor that typically runs in a text window, where the user types commands that cause actions. Bash can
also read commands from a file, called a script. Like all Unix shells, it supports filename globbing (wildcard matching), piping,
here documents, command substitution, variables and control structures for condition-testing and iteration. The keywords, syntax
and other basic features of the language were all copied from sh. Other features, e.g., history, were copied from csh and ksh.
Bash is a POSIX shell, but with a number of extensions. (https://bit.ly/2bBmYap)
In this ebook, we provide a compilation of BASH programming examples that will help you kick-start your own projects. We
cover a wide range of topics, from user management and permissions setting, to specific commands like sed, tar, etc. With our
straightforward tutorials, you will be able to get your own projects up and running in minimum time.
Linux BASH Programming Cookbook ix
SCGs (System Code Geeks) is an independent online community focused on creating the ultimate Operating System developers
resource center; targeted at the technical architect, technical team lead (senior developer), project manager and junior developers
alike.
SCGs serve the OS developer, OS engineer and DevOps communities with daily news written by domain experts, articles,
tutorials, reviews, announcements, code snippets and open source projects.
You can find them online at https://www.systemcodegeeks.com/
Linux BASH Programming Cookbook 1 / 55
Chapter 1
Linux find command is a powerful and flexible search tool that not only every system administrator must master, but also any
kind of Linux user. This tutorial will show how to use it to perform almost any type search with this useful command.
For this tutorial, Linux Mint 17.3 and find 4.4.2 have been used.
To find, for example, README.txt files in home directory, we would type the following:
find /home -name README.txt
The -name expression is case sensitive. The following command will find every README.txt file in the whole disk, not taking
into account the case sensitivity:
find / -iname README.txt
Using regular expressions is useful mostly when we are looking for certain type of files.
For example, to find every .txt file in the home directory, the regular expression would be:
find /home -regextype posix-extended -regex ".*\.txt"
• With -regextype we are specifying a regular expression type, posix-extended, which is more widely implemented in
other systems than find ’s default one.
• And the regular expression itself:
– The * is for searching zero or more repetitions. Combined with ., will look for every file in the specified directory, because
every file will have at least a character, repeated zero or more times.
– Once that we have looked for every file, we have to filter the results. In this case, we are finding for every string ending in .
txt. Note that we have escaped the dot character, with ., since it’s a special character for regex.
Regular expressions can be as flexible as we want. We can find every .txt and .log files with the following command:
find /home -regextype posix-extended -regex ".*(\.txt|\.log)"
What we are doing is to tell find to look for every file ending with the .txt substring or with the .log substring. The | character is
an or operand. And everything inside round braces, is for matching that exact substring.
We have seen how to match exact substrings. Now, let’s see how to match characters inside a range. For that, we will find files
that have numbers in their name:
find /home -regextype posix-extended -regex ".*[0-9]"
The square brackets are for matching specific characters (not strings). And we can define ranges with the hyphen.
To end with this section, let’s see how we would find files that are composed by a date (supposing it in UK format):
find /home -regextype posix-extended -regex ".*[0-9]{2}-[0-9]{2}-[0-9]{4}.*"
The curly braces are used for repetitions. So, we are looking for something with *XX-XX-XXXX* format.
Note: for finding files by their extension, there’s a shorter way using -name :
find /home -name "*.txt"
Which is a more appropriate option when we want to make a search specifying an unique file extension.
Apart from the name, we can also find for some specific file properties. In this section we will see for which properties we can
make searches, and how.
1.2.1.1 In minutes
There are many cases in which we can be interested in finding by the time they have been modified (as same as when we sort by
modification time when using a GUI).
We can look for files that have been modified, for example, in the last 30 minutes:
find /home -mmin -30
Note that we are using a hyphen when specifying the minutes. Without it, find would look for files that have been modificated
exactly 30 minutes ago:
find /home -mmin 30
For finding files by access time, is almost the same than for modification time, but with -amin expression instead of -mmin :
find /home -amin -30
There’s another property for finding through the time, that is the change time. Don’t confuse it with modification time. The
change time is a status change (for example, permission or owner change).
As you probably have guessed, for finding by status change time, we have to use the -cmin expression:
find /home -cmin -30
Linux BASH Programming Cookbook 3 / 55
1.2.2 In days
We have seen how find files through time, specifying the time in minutes. But we can also make searches specifying the time in
days. For that, we have to change the *min suffix of the previous expressions, with *time suffix.
Take into account that the searches made with *time are always truncated. So, if we want to find modified files between the
current moment and the previous day, we have to type:
find /home -mtime 0
1.2.3 By permissions
Finding files by permissions is so simple. We can look for files belonging to a certain user or group:
find /home -user julen
find /home -group development
The above command would find the files with exactly 777 permissions, which can be useful to find files with permissions that
should be fixed.
There is the dash prefix available, /, for finding files that match at least one of the specified permission bits. It’s easier to
understand seen in an example:
find / -perm /755
The above command would find files that are readable, writable or executable by the owner; readable or executable by the owner
group; or readable or executable by other users. Finds
Of course, we can also use the symbolic notation to find files by permissions:
find / -perm a=rwx
You may noticed that find also returns folders, for example. By default, find looks for every file that matches with the criteria,
regardless its type.
If we are only looking for a certain type of files, we have to specify it with -type:
find / -perm a=rwx -type f
• d: directory
• f: regular file
• l: symbolic link
• b: buffered block
• c: unbuffered character
• p: named pipe
• s: socket
Linux BASH Programming Cookbook 4 / 55
1.2.5 By size
Finding by size is specially useful when we can to free some space in the disk. And is pretty simple:
find /var/log -size +20M
The above command will find files bigger than 20 megabytes in /var/log directory, a typical directory whose size has to be
continuously watched by systems administrators.
We have several units to choose:
• M: megabytes
• G: gigabytes
Which, respectively, mean: "find every file bigger than 10MB and with .txt extension", "find every file with 777 permissions
that does not belong to root user", and "find every file that belongs to developer user or to development group".
Actually, the -and expression is not necessary to combine expressions with and logic.
find / -size +10M -name "*.txt"
The command shown above would work as same as the previous one with -and.
This is the most powerful feature of find. The -exec option allows us to execute commands for every found file.
A very typical use of -exec is for showing file information as we would do with ls command:
find / -size +500M -exec ls -l {} \;
Apart from executing the command after -exec option, we have to add {}, where the file returned by find will be placed, like
passing a parameter to the specified command. And the ; is to set the command end. We can chain multiple -exec commands
after the command end.
Linux BASH Programming Cookbook 5 / 55
To end with the tutorial, we will see some of the most common find commands.
Delete old and big log files
find / -iname "*.log" -mtime +1 -size +10M -exec rm {} \;
1.6 Conclusion
In this tutorial we have seen how to deal with Linux find command, a very powerful tool for file search, from simple searches,
like by name or extension; to more advanced ones, using complex regular expressions or filtering by permissions, and also being
able to execute any commands for every search we make.
Linux BASH Programming Cookbook 6 / 55
Chapter 2
Screen is a window manager that allows to have several virtual terminals, several sessions and programs in text mode executing
simultaneously in the same console. In this tutorial we will see how to use it.
For this tutorial, Linux Mint 18 has been used.
2.1 Installation
If you don’t have installed Screen, you can install it easily with apt-get:
sudo apt-get update
sudo apt-get install screen
We will see an informative screen about the software itself. Just hit return to exit.
At this moment, a new screen will be generated inside the terminal window. You may have noticed it, since the buffer has been
cleared.
And that’s it!
This has created a pipe file for this session in /var/run/screen/S-<username>/ directory. The username I’m working
with is named julen, so, the directory is /var/run/screen/S-julen/.
In my case, the name for the session is 3360.pts-0.julen-VAIO. screen generates the sessions with the following
format:
<pid>.<tty>.<host>
You may be wondering how to exit the screen. You can obviously close the terminal, but that would leave the session alive. If
you want to kill it, you can execute the following command inside the session you want to kill:
exit
You will see that you return to the "original" shell, and that screen has told that, effectively, you have exited its screen:
[screen is terminating]
If you check the directory where screen saves the sessions, you will notice that the previous session has disappeared.
Linux BASH Programming Cookbook 7 / 55
We have seen that executing screen in the host computer, creates a new session, which is saved in /var/run/screen/S-
<username>/ directory. If we would execute screen n times in the host, we would have n sessions.
Inside each session, we can have other several screens, named windows. The windows are created, again, executing the screen
command. So, the following:
screen
# We are know inside a screen session
screen
This is because, as we have said, executing screen inside a screen session will create a window inside that screen, not another
session.
In the next sections we will see the commands available for these screens.
screen command has many inline options. The following table shows and explains them.
Linux BASH Programming Cookbook 8 / 55
When we are inside a screen and its windows, we have available some special key combinations to perform some actions, e.g.,
navigating through different windows.
These key bindings consist on pressing Ctrl + a, and then pressing the key(s) in question. Not at the same time: first, Ctrl + a;
then, release them; and finally, press the key in question.
The following table shows the most used key bindings.
Linux BASH Programming Cookbook 9 / 55
screen allows us to configure it as we want. It looks for the configuration in a file named .screenrc in the user’s home
directory; or system wide, in /etc/screenrc.
You may already be tired of the startup message when you create a screen, that one about the version, copyright, etc. This can be
disabled with the following line in the configuration file:
startup_message off
One of the most interesting possibilities is defining a set of default windows for every screen session. For that, we just have to
write the commands we would execute, in the configuration file.
For example, let’s say that for every screen session we want, apart from a shell, a Python and PHP console. We could write
the following in the configuration file:
Linux BASH Programming Cookbook 10 / 55
Now, for the configuration shown above, you would have, for each screen session, those three windows.
The remaining customization that is worth mentioning is the configuration of key bindings, for having a better experience.
A usual practice is to use the function keys (F1 - F12). For example, we could use them for accessing windows:
bindkey "^[[[A" select 1 # F1 -> window 1
bindkey "^[OQ" select 2 # F2 -> window 2
bindkey "^[OR" select 3 # F3 -> window 3
bindkey "^[OS" select 4 # F4 -> window 4
bindkey "^[[15~" select 5 # F5 -> window 5
bindkey "^[[17~" select 6 # F6 -> window 6
bindkey "^[[18~" select 7 # F7 -> window 7
bindkey "^[[19~" select 8 # F8 -> window 8
bindkey "^[[20~" select 9 # F9 -> window 9
bindkey "^[[21~" select 10 # F10 -> window 10
bindkey "^[[23~" prev # F11 -> previous window
bindkey "^[[24~" next # F12 -> next window
Note: if you want to know which key code corresponds to each keystroke, you can use showkey:
showkey -a
2.6 Summary
In this tutorial we have seen how to use the Screen utility, for managing several virtual windows in the same terminal. We have
seen the command’s inline options, and also the special key combinations for when we are inside the virtual windows. To end up
with the tutorial, we have shown how we can customize Screen with the configuration file.
Linux BASH Programming Cookbook 11 / 55
Chapter 3
3.1 Introduction
In this example, we will see how to use the Unix-like system command chown
The chown command changes the owner and owning group of files.
If you are on Windows OS, before we get into the details of this command, I would suggest you to have a Linux machine for
better understanding of the usage of this command.
Not necessarily you need to physically have a separate machine. You can very much have a virtual Linux machine on a virtual
box like Oracle VirtualBox.
3.2 Syntax
3.3 Description
chown changes the user and/or group ownership of each given file.
If only an owner is given, that user is made the owner of each given file, and the files’ group is not changed.
If the owner is followed by a colon and a group name, with no spaces between them, the group ownership of the files is changed
as well.
If a colon but no group name follows the user name, that user is made the owner of the files and the group of the files is changed
to that user’s login group.
If the colon and group are given, but the owner is omitted, only the group of the files is changed; in this case, chown performs the
same function as chgrp. If only a colon is given, or if the entire operand is empty, neither the owner nor the group is changed.
3.4 Options
-c, --changes like verbose but report only when a change is made.
-f, --silent, --quiet suppress most error messages.
-v, --verbose output a diagnostic for every file processed.
--dereference affect the referenced file of each symbolic link rather than
the symbolic link itself. This is the default.
-h, --no-dereference affect symbolic links instead of any referenced file. This is
useful only on systems that can change the ownership of a
symlink.
--from=CURRENT_OWNER:CURRENT_GROUP change the owner and/or group of each file only if its
current owner and/or group match those specified here.
Either may be omitted, in which case a match is not
required for the omitted attribute.
--no-preserve-root do not treat / (the root directory) in any special way. This is
the default.
--preserve-root Do not operate recursively on /.
--reference=RFILE use RFILE’s owner and group rather than specifying
OWNER:GROUP values
-R, --recursive operate on files and directories recursively.
The following options modify how a hierarchy is traversed when the -R option is also specified. If more than one is specified,
only the final one takes effect.
Owner is unchanged if unspecified. Group is unchanged if unspecified, or changed to the login group if implied by a : following
a symbolic OWNER. OWNER and GROUP may be numeric as well as symbolic.
3.5 Examples
We will see the details of the information given above with yellow rectangle mark.
• 1st Character - File Type: First character specifies the type of the file.
In the picture above the d in the 1st character indicates that this is a directory.
Following are the possible file type options in the 1st character of the ls -l output.
• Field Explanation
• - normal file
• d directory
• s socket file
• l link file
Field 5 - Size: Fifth field specifies the size of file. In this example, ’4096’ indicates the file size.
Field 6 - Last modified date & time: Sixth field specifies the date and time of the last modification of the file. In this example,
Jan 15 19:46 specifies the last modification time of the file.
Field 7 - File name: The last field is the name of the file/directory. In this example, the file name is gmr.
Please refer the image shown below. In this the user owner of a folder has been changed to a new user.
But, user owner has been changed only for the directory projects. Ownership of the inner files or directories will remain the
same, unchanged.
If the flag -R is used, it will change the owner for inner files / directories also.
Recursively grant ownership of the directory projects, and all files and sub-directories, to user gmr.
chown -R gmr projects
As shown below, ownership of javadocs folder has been copied to projects folder.
Using chown command, the group (that a file belongs to) can also be changed.
Linux BASH Programming Cookbook 16 / 55
3.6 Conclusion
In this example, we have seen how to use Linux command chown with different options.
Linux BASH Programming Cookbook 17 / 55
Chapter 4
One of the most critical jobs a system administrator has to continuously be dealing with is the permission administration. The
most small carelessness with the permissions can lead to a security hole in the system.
This example will show how are changed the permissions, a task for which chmod command is used
For this example, Linux Mint 17.3 has been used.
What makes the Linux permission system so great is its simplicity, specially when it’s compared to others, such us Windows’. In
any case, we will see briefly how it works.
There are three main things that have to be understood: the elements the permissions are defined for, the actions that can be
performed, and who can perform them.
The elements are two:
• Files.
• Directories.
• Read
• Write.
• Execute. Apart from for executing scripts and binaries, also corresponds to folders: to create files and other folders inside it.
To see how the permissions are organized, we can list the files in the terminal:
ls -l
The first section, 10 characters, are which correspond to permissions. Let’s examine it:
• The first character is for file type. - means that the file is a regular file, and d means that is a directory.
• The following nine characters are for read (r), write (w) and execute (x) permissions for the owner, the group of the owner,
and others, respectively.
To change the permissions, the chmod command (contraction of change and mode) is used. The syntax is the following:
chmod permissions file [file 2] [file n]
The specification of the files seems quite obvious, but, how are the permissions specified?
We can try to read the file with a user that is not the owner and does not belong the the owner’s group, to see what happens:
sudo -u other-user more file.txt
• 0 for no permission.
• 1 is for execution permission.
So, for assigning read and write permissions, what we have done is 2 + 4 =6.
The following table shows the permissions that gives each digit:
Linux BASH Programming Cookbook 19 / 55
• u: file owner.
The actions are represented with the same symbols that we have seen before:
• r: read.
• w: write.
• x: execute.
• -: removes permissions.
For example, the previous example (owner: read and write; group: read; others: none) with the symbolic notation, would be the
following:
Linux BASH Programming Cookbook 20 / 55
As you can see, for this example, this notation requires much more verbosity.
But for other cases is more suitable. For example, if we want to maintain the current permissions, but allowing now everybody
to write, we would have to type:
sudo chmod a+w file.txt
To these ones:
-rw-rw--w- 1 julen julen 0 Jun 26 17:39 file.txt
Apart from those permissions we have seen, there are three more special permissions in Linux: the setuid (user id), the
setgid (group id), and the sticky.
4.3.1 setuid
The setuid bit (set user ID) can be assigned to executable files, which is for, when a file is executed, allow the process acquire
that file’s owner’s permissions. This is generally used to allow normal users (those without superuser privileges) to obtain
root privileges for some executables.
This can be seen, for example, in common binaries, such us /bin/ping. If we check its permissions, we will see that it has the
setuid bit bit assigned:
-rwsr-xr-x 1 root root 44168 May 7 2014 /bin/ping*
Which is expressed with a s, in the place for the execution bit for the owner.
If we remove the setuid bit from that executable:
sudo chmod u-s /bin/ping
A normal user won’t be able to use ping, and if it would try to use it:
ping localhost
Of course, an user with sudo permissions could execute the command with root privileges, but, as said before, this bit is though
for users that don’t have superuser privileges.
To add the setuid bit again:
sudo chmod u+s /bin/ping
Linux BASH Programming Cookbook 21 / 55
4.3.2 setgid
If the setuid bit allows the user acquire the permissions of the owner, the setgid (set group id) allows to acquire the
permissions of the group.
The bit can be set as follows with the octal notation:
sudo chmod 2777 script.sh
If the setuid bit was placed in the owner’s execution bit place, in this case, is placed in the group’s execution’s place:
-rwxrwsrwx 1 julen julen 14 Jun 27 19:22 script.sh*
4.3.3 sticky
The sticky bit is used in directories, when we want a file, or folder writable for several users, but where files and folders
inside it can only be deleted by the owner. This bit is used, for example, in /tmp and /var/tmp directories.
The sticky bit can be assigned the following way:
sudo chmod 1777 sticky/
Where the sticky bit is set with the leading 1, and then, the wanted permissions (which usually are 777 for this cases).
And, with symbolic notation:
sudo chmod +t sticky/
The sticky bit is expressed with a t in the place for the execution bit for others:
drwxrwxrwt 2 julen julen 4096 Jun 27 19:22 sticky/
We can see how it works, we can create a file in our sticky/ directory, try to modify it with the owner and other user, and also
to delete it:
touch file.txt
echo "written with owner" > file.txt
sudo -u other-user echo "written with other user" > file.txt
Which would work. But if we try to delete it with the user that is not the owner. . .
sudo -u other-user rm file.txt
4.4 Summary
In this example, we have first seen very briefly how the Linux permission, identifying the main concepts that are involved when
dealing with permissions. Then, we have seen how the permissions are changed for the different notations, and, to end up with
the example, we have taken a look for the special permissions bits that are available in Linux.
Linux BASH Programming Cookbook 23 / 55
Chapter 5
This example will show you how to create users in Linux, looking at the two different available commands: the default utility,
useradd; and a script that acts as more friendly front-end for the default utility, which is named adduser.
For this example, Linux Mint 17.03 has been used.
The existing users of the system are registered in the file /etc/passwd. This file defines who has legit access to the system.
This is an example of a line of the file:
julen:x:1000:1000:Julen Pardo:/home/julen:/bin/bash
It’s better not to touch manually this file to add (or modify/remove) users. To add users, we should use the methods that we
will see in this tutorial.
useradd is the native, low level, binary of Linux systems. Its use is very simple:
sudo useradd [options] username # superuser privileges are needed.
Now, a new user named john_doe has been created in the users database. We can check it in the /etc/passwd file:
grep "john_doe" /etc/passwd
We have created a user without a password! We can check it in the /etc/shadow file:
grep "john_doe" /etc/shadow
Returning:
john_doe:!:17018:0:99999:7:::
That exclamation mark ! means that no password is set for the user.
Setting a password for each user is not an advice, but mandatory. For this, we have two options: create the user and then
set the password (with passwd command), or specify it at creation time with -p (--password) option. The recommended
option is the first one, since the second one has two obvious downsides:
Use always the passwd command to set the passwords. We only have to run it specifying the user, as in the following
example:
sudo passwd john_doe
Now that we have this new user, we can try to login in the system with it:
sudo -u john_doe -i # Login with user john_doe.
This will create a directory for the new user. The default behavior for this option is to create the directory with the same name as
the created user, in the /home directory.
Linux BASH Programming Cookbook 25 / 55
For some reason, we might want to set the home directory in a different place from /home. This is allowed using the -b (--
base-dir) option. For example:
sudo useradd john_doe -b /tmp
Note that we only have specified the directory where the home directory will be placed, not the home directory name itself.
When we use this option, we also have to tell userrad to create the home directory, as in the example of the previous section:
sudo useradd john_doe -b /tmp -m
You may have noticed that the in the line for our user, the value for the shell is not set. Usually, we would want to use /bin/
bash instead of the default /bin/sh. To specify the shell, we have to use the -s (--shell) option:
sudo useradd john_doe -m -s /bin/bash
The default behavior when creating a user is to create a group for it, with the same name, and set it as primary. But we have the
option to avoid this and specify a group name (or gid) to be the primary of the creating user. For this, -g (--gid) option is
used, as in the following example:
sudo useradd john_doe -g developers
And john_doe will be created with developers as primary group. We can check it with the groups command:
groups john_doe
Similarly to the primary group, we may want to set secondary group(s) for a user at creation time. This time, -G (-groups)
option has to be used, specifying the list of groups separated by commas, without whitespaces, e.g.:
sudo useradd john_doe -G developers,another_secondary
This option is useful when we have to create accounts for users that we know beforehand have to have access to the system only
until a certain date. For this, we have to use the -e (--expiredate) option, specifying the date in YYYY-MM-DD format.
Let’s see it with an example:
sudo useradd john_doe -e 2017-01-01
Linux BASH Programming Cookbook 26 / 55
Actually, we can set any type of additional comments, but this option is usually used to specify personal information, such as
real name. We have to use the -c (--comment) option, specifying the information between quotes (single or double, doesn’t
matter) if the comment contains whitespaces, e.g.:
sudo useradd john_doe -c ’John Doe’
With useradd, we have seen that creating users is not actually difficult, but, by default, it doesn’t perform some actions that
can be supposed as essential, like creating the home directory. We can even create a user without a password, and do not notice
it.
To make user creation easier and in a more comfortable way, adduser was created. This is just a Perl script for an interactive
use of useradd.
If we try to create a user with adduser, e.g.:
sudo adduser john_doe
And we will see that, only typing that, adduser does many things for us:
Adding user ’john_doe’ ...
Adding new group ’john_doe’ (1001) ...
Adding new user ’john_doe’ (1002) with group ’john_doe’ ...
Creating home directory ’/home/john_doe’ ...
Copying files from ’/etc/skel’ ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for john_doe
Enter the new value, or press ENTER for the default
Full Name []: John Doe
Room Number []: 1
Work Phone []: 111-111-111
Home Phone []: 222-222-222
Other []: 333-333-333
Is the information correct? [Y/n] Y
Even if adduser does makes more comfortable the user creation, we can change the options. Let’s see the equivalents for
adduser that we have seen for useradd.
The format is the same as with useradd:
Linux BASH Programming Cookbook 27 / 55
The adduser utility does not provide options for setting secondary groups and and an expiration date.
5.4 Summary
This example has shown how to create users in Linux systems, with two different commands: useradd and adduser. As
we have seen, adduser can be considered a better (in terms of usability) option, since it performs two essential actions that
useradd does not perform by default: create a home directory, and set a password. Even if a user creation can require more
options, those two are always fundamental.
Linux BASH Programming Cookbook 28 / 55
Chapter 6
In this tutorial we will see how to add users to groups in Linux, looking at the different possibilities (existing or non-existing
users), and taking into account also the different types of groups users can belong to (primary and secondary groups).
For this example, Linux Mint 17.03 has been used.
Linux defines the groups in the file /etc/group. If we open it, we will see many rows, with the following format:
adm:x:4:syslog,julen
• The group_name is the name we give to the group when we create it with groupadd.
• The password is optional. Really, this is almost never used.
• The gid (group identifier) is the numerical identifier that each group has.
• Finally, the members of the group are listed.
It is possible to modify this file manually, but also dangerous, since it can become corrupt. In any case, there is available a tool
for checking the integrity of this file, called grpck. To use it, just execute it with sudo permissions. If the file is correct, no
message will be shown. In any case, is not recommendable to modify it manually.
It is necessary to know that Linux distinguishes two types of groups for a user: the primary, and secondaries. The primary group
is the one used when the user creates files and directories. Let’s suppose that we have a user named john_doe, whose primary
group is developers, but that is enrolled also in a group called testers. Every file created by him:
touch foo
To see to which groups a user belongs to, we can use the groups command, specifying the user name:
groups <username>
That is, the primary group will be the first of the list (or the unique, if the user does not belong to more groups).
Linux BASH Programming Cookbook 29 / 55
When we are going to create a new user, with useradd, we can specify its group(s), so we can create users and assign groups
to it with one command.
The primary group is configured with -g (--gid) option. For example, to create a john_doe user with the developers
group as primary, we would have to type:
sudo useradd john_doe -g developers
(Remember to always assign a password to each new user, with passwd command.)
We can check that it has been created as expected, using groups command:
groups john_doe
If no primary group is specified, the assignation of the primary group will depend on the configuration defined in /etc/login.
defs. If the variable USERGROUP_ENAB is set to yes, the primary group of the user will be a new group with the same name
as the username. If the variable is set to no, the primary group of the user will be the one specified in /etc/default/
useradd, in the GROUP variable.
So, if we assume that every user created in the future has to have a specific group as primary, e.g., developers, we first have
to edit the /etc/login.defs file:
USERGROUP_ENAB no
The second and last step is to specify the group in /etc/default/useradd file:
GROUP=developers
The option for assigning secondary groups to the user that is going to be created is -G (--groups), specifying the list of groups
separated by commas, without whitespaces. For example:
sudo useradd john_doe -G developers,testers
Would create the john_doe user, with developers and testers groups as secondary.
john_doe : john_doe developers testers
The usermod command, as its name suggests, is for modifying users, in all its facets, including their groups.
For the modification of groups, it works exactly as with useradd: -g for modifying the primary group, and -G for the secondary
ones.
Linux BASH Programming Cookbook 30 / 55
Changing the primary group of an existing user is pretty simple, we just have to use the -g option for the useradd, as told
before:
sudo usermod john_doe -g developers # Now primary group of ’john_doe’ is ’developers’.
The manual of useradd warns about changing the primary group of a user:
Any file from the user’s home directory owned by the previous primary group of the user ←-
will be owned by this new group.
The group ownership of files outside of the user’s home directory must be fixed manually.
This manual fixing for the whole disk can be easily done with find. Let’s suppose that we have changed john_doe user’s
primary group from john_doe to developers, and that we want to change the owner of every file to this one. We could
execute the following:
sudo find / -group john_doe -exec chgrp developers {} \;
Finding every file in / and subdirectories (i.e., all the disk) that has john_doe as group owner, executing for each result a
chgrp to change to group owner to developers.
Let’s suppose that we have a john_doe user with the following output for groups:
john_doe : john_doe
Now, we want to assign some groups, developers and testers, to the existing john_doe user. We would just have to
execute the usermod command with the -G option, specifying the groups:
sudo usermod john_doe -G developers,testers
According to the manual of usermod, this is what happens when using -G option:
[...] If the user is currently a member of a group which is not listed, the user will
be removed from the group.This behavior can be changed via the -a option, which append
s the user to the current supplementary group list.
In the previous case, we can see that the group that john_doe was already belonging to (the primary), has not disappeared, but
this is just because it was the primary group. Note that, with the current groups for john_doe, the following:
sudo usermod john_doe -G another_group
Users are given sudo permissions by just being added to sudo group. So, the only thing we have to do is to add the users to
sudo group, as same as we have been seeing in this example:
sudo useradd john_doe -G sudo # At creation time.
sudo usermod john_doe -G sudo -a # For existing user.
Linux BASH Programming Cookbook 31 / 55
6.5 Summary
This example has shown how to add users to groups, for both non-existing, and already existing users, taking into account also
the differences between the primary group and the secondary ones, considering also the side effects of a primary group change,
and proposing an easy fix to them.
Linux BASH Programming Cookbook 32 / 55
Chapter 7
I am a real fan of learning Linux commands by examples and from my personal experience it will really help to see some Linux
tar command examples. But first, a brief bit of background information. The name "tar" stands for "tape archive".
As that name implies, originally it was a command that Unix administrators used to deal with tape drives. Where we now use the
Linux tar command to create a tar file, we used to tell it to write the tar archive to a device file (e.g in /dev).
Nowadays the Linux tar command is more often used to create compressed archives that can easily be moved around, from one
disk to anther disk or machine to machine, in other words we can call it as backup utility and its been used in most of the Unix
flavors. One user may archive a large collection of files, and another user may extract those files, with both of them using the tar
command.
In this example we will come to know basic tar command using option cvf to create a tar archive. Here we are creating a tar file
my-archive.tar for a directory /home/my-directory in current working directory:
[root@chasiota /]# tar cvf my-archive.tar /home/my-directory
c - Creates a new .tar archive file v - Verbosely list files which are processed f - File name type of the archive file
In order to make tar ball as zipped archive , we need to use the option "z". In below example the command will make "my-
archive.tar.gz" for a directory "/home/my-directory" in current working directory.
[root@chasiota /]# tar cvzf my-archive.tar.gz /home/my-directory
To list the contents of an uncompressed tar archive, just replace the cflag with the tflag, like this:
[root@chasiota /]# tar tvf my-archive.tar
This lists all the files in the archive, but does not extract them. To list all the files in a compressed archive, add the zflag like
before:
[root@chasiota /]# tar tzvf my-archive.tgz
Linux BASH Programming Cookbook 33 / 55
To extract the contents of a Linux tar archive, now just replace the tflag with the x("extract") flag. For uncompressed archives the
extract command looks like this:
[root@chasiota /]# tar xvf my-archive.tar
For compressed archives the tar extract command looks like this:
[root@chasiota /]# tar xzvf my-archive.tar.gz
In order to extract the contents of a *.tar.bz2 file the options are "xj".
[root@chasiota /]# tar xvjf my-archive.tar.bz2
To extract a specific file from a tar archive, specify the file name at the end of the tar xvf command as shown below. The following
command extracts only a specific file (my-file.sh) in the current directory from a large tar file.
[root@chasiota /]# tar xvf my-archive.tar my-file.sh
Many times when using the Linux tar command you will want to create an archive of all files in the current directory, including
all subdirectories. You can easily create this archive like this:
[root@chasiota /]# tar czvf my-directory.tgz .
In the above example, the . at the end of the command is how you refer to the current directory.
Linux BASH Programming Cookbook 35 / 55
You may also want to create a new tar archive like that previous example in a different directory, like this:
[root@chasiota /]# tar czvf /tmp/my-directory.tgz .
As you can see, you just add a path before the name of your tar archive to specify what directory the archive should be created
in.
To extract a single directory (along with its subdirectory and files) from a tar archive, specify the directory name at the end of the
tar xvf command as shown below. The following extracts only a specific directory from a large tar file:
[root@chasiota /]# tar xvf my-archive.tar home/my-directory/
7.11 Check the size of the tar, tar.gz and tar.bz2 Archive File
For any tar, tar.gz and tar.bz2 archive file, the below commands will display the size of archive file in Kilobytes (KB):
[root@chasiota /]# tar -cf - my-archive.tar | wc -l
As part of creating a tar file, you can verify the integrity of the archive file that got created using the option “W” as shown below:
[root@chasiota /]# tar tvfW my-archive.tar
If an output line starts with Verify, and there is no differs line then the file/directory is OK. If not, you should investigate the
issue.
Note: for a compressed archive file ( *.tar.gz, *.tar.bz2 ) you cannot do the verification.
Finding the difference between an archive and file system can be done even for a compressed archive. It also shows the same
output as above excluding the lines with Verify.
Finding the difference between gzip archive file and file system:
[root@chasiota /]# tar dfz my-archive.tgz
Finding the difference between bzip2 archive file and file system:
[root@chasiota /]# tar dfj my-archive.tar.bz2
You can use the following syntax to delete a file from a tar ball:
[root@chasiota /]# tar --delete -f my-archive.tar home/my-file
You can add additional files to an existing tar archive with “r” option:
[root@chasiota /]# tar rvf my-archive.tar my-file
Linux BASH Programming Cookbook 37 / 55
Adding a directory is also the same. We need to mention the directory name instead of the file name:
[root@chasiota /]# tar rvf my-archive.tar my-dir/
7.17 Extract group of files from tar, tar.gz, tar.bz2 archives using regular expres-
sion
You can specify a regular expressions , to extract files matching a specified pattern. For example, the following tar command
extracts all the files whose file ends with .java:
[root@chasiota /]# tar xvf my-archive.tar --wildcards ’*.java’
7.18 Untar multiple files from tar, tar.gz and tar.bz2 File
To extract or untar multiple files from the tar, tar.gz and tar.bz2 archive file. For example the below command will extract
“my-file-1” “my-file-2” and "my-file-3" from the archive files:
[root@chasiota /]# tar -xvf my-archive.tar "my-file-1" "my-file-2" "my-file-3"
More important than performing regular backups is having them available when we need to recover important files. The following
command will restore all files from the full-backup-Day-Month-Year.tar archive, which is an example backup of our home
directory:
[root@chasiota /]# tar xpf /dev/st0/full-backup-Day-Month-Year.tar
You can always refer to the manual page for all available tar commands:
[root@chasiota /]# man tar
Linux BASH Programming Cookbook 39 / 55
Chapter 8
Sed is basically a stream editor used for modifying files in unix or linux. It provides a nifty way to perform operations on files
which can be passed around through pipes. Most people never learn its real power, they just simply use sed to replace text. You
can do many things apart from replacing text with sed.
As mentioned earlier, sed is an editor that allows us to use pattern matching to search and replace within a file, or an input stream.
This works by using Regular Expressions. By default, the results of any edits we make to a source file, or input stream, will be
sent to STDOUT, the standard output. The original file will be unaffected by the edits.
Also the sed command can be incredibly useful when bootstrapping a new server, or machine, as it can easily be scripted. A
common use case for sed is to script the editing of configuration files on a new server instance to facilitate the further setup of
the needed environment for that machine.
In this article I will describe the capabilities of sed with examples. Consider the below file as input to our examples:
>cat example.txt
I want to learn java. Learn java. Learn java
java is the best
java forever
Sed command is mostly used to replace the text in a file. The below sed command replaces the word "java" with "guava" in the
file only for the first occurrence in each line:
>sed ’s/java/guava/’ example.txt
Here the "s" specifies the substitution operation. The "/" are delimiters. The "java" is the search pattern and the "guava" is the
replacement string.
By default, the sed command replaces the first occurrence of the pattern in each line and it won’t replace next occurences.
Use the /1, /2 etc flags to replace the first, second occurrence of a pattern in a line. The below command replaces the second
occurrence of the word "java" with "guava" in a line:
>sed ’s/java/guava/2’ example.txt
Linux BASH Programming Cookbook 40 / 55
The substitute flag /g (global replacement) specifies the sed command to replace all the occurrences of the string in the line:
>sed ’s/java/guava/g’ example.txt
Use the combination of /1, /2, /n and /g to replace all the patterns from the nth occurrence of a pattern in a line. The following
sed command replaces from the second occurrence until the nth of the word "java" with the word "guava" in a line:
>sed ’s/java/guava/2g’ example.txt
The /p print flag prints the replaced line twice on the terminal. If a line does not have the search pattern and is not replaced, then
the /p prints that line only once.
>sed ’s/java/guava/p’ example.txt
The below image illustrates the execution of the first 5 sed commands:
Linux BASH Programming Cookbook 41 / 55
You can restrict the sed command to replace the string on a specific line number. The below sed command replaces the string
"java" only on the second line:
>sed ’2 s/java/guava/’ example.txt
You can specify a range of line numbers to the sed command for replacing a string. Here the sed command replaces the lines
with range from 1 to 3. You may use the $ operator to indicate the last line in the file:
>sed ’1,$ s/java/guava/’ example.txt
You can specify a pattern to the sed command to match in a line. If the pattern match occurs, then the sed command looks only
for the string to be replaced and if it finds it, then it replaces the string. Here the sed command first looks for the lines which have
Linux BASH Programming Cookbook 42 / 55
the pattern "java" and then replaces the word "java" with "guava".
>sed ’/java/ s/java/guava/’ example.txt
You can delete the lines of a file by specifying the line number or a range of numbers:
>sed ’2 d’ example.txt
You can use the sed command to print each line of a file two times:
>sed ’p’ example.txt
The below image illustrates the execution of the previous 5 sed commands:
You can use any delimiter other than the slash. As an example if you want to change the web url to another url, using too many
backslashes makes the sed command look awkward. In this case we can change the delimiter to another character as shown in
the below example:
>sed ’s_https://_www_’ example.txt
There might be cases where you want to search for the pattern and replace that pattern by adding some extra characters to it. In
such cases & comes in handy. The & represents the matched string:
>sed ’s/java/{&}/’ example.txt
The first pair of parenthesis specified in the pattern represents the 1, the second represents the 2 and so on. The 1,2 can be used
in the replacement string to make changes to the source string. As an example, if you want to replace the word "java" in a line
with twice as the word like "javajava" use the sed command as below:
>sed ’s/\(java\)/\1\1/’ example.txt
You can run multiple sed commands by piping the output of one sed command as input to another sed command. Sed provides
also an -e option to run multiple sed commands in a single sed command:
>sed ’s/java/guava/’ example.txt | sed ’s/guava/python/’
Use the -n option along with the /p print flag to display only the replaced lines. Here the -n option suppresses the duplicate rows
generated by the /p flag and prints the replaced lines only one time:
>sed -n ’s/java/guava/p’ example.txt
The below image illustrates the execution of the previous 5 sed commands:
Linux BASH Programming Cookbook 44 / 55
You can make sed command to work as similar to grep command. Here the sed command looks for the pattern "java" in each
line of a file and prints those lines that have the pattern:
>grep ’java’ example.txt
The sed command can add a new line after a pattern match is found. The "a" command to sed tells it to add a new line after a
match is found:
>sed ’/java/ a "Add a new line"’ example.txt
Linux BASH Programming Cookbook 45 / 55
The sed command can add a new line before a pattern match is found. The "i" command to sed tells it to add a new line before a
match is found:
>sed ’/java/ i "New line"’ example.txt
The sed command can be used to replace an entire line with a new line if a match is found. The "c" command to sed tells it to
change the line.
>sed ’/java/ c "Change line"’ example.txt
The sed command can be used to convert the lower case letters to upper case letters by using the transform "y" option. In the
below example the sed command transforms the alphabets "av" into their uppercase format "AV"
>sed ’y/av/AV/’ example.txt
The below image illustrates the execution of the last 5 sed commands:
We tried to present some basic examples of using the sed command. Of course you may always use the man command to find
the full functionality of the sed command:
>man sed
Linux BASH Programming Cookbook 47 / 55
Chapter 9
Cut is a Unix command line utility which is used to extract sections from each line of input, usually from a file. It is currently
part of the GNU coreutils package and the BSD Base System. It first appeared in AT&T System III UNIX in 1982. Extraction of
line segments can typically be done by bytes (-b), characters (-c), or fields (-f) separated by a delimiter (-d - the tab character by
default).
A range must be provided in each case which consists of one of N, N-M, N- (N to the end of the line), or -M (beginning of the
line to M), where N and M are counted from 1 (there is no zeroth value). Basically the cut command slices a line and extracts
the text.
In this article, we will start with a few basic examples and then explore all the advanced options that cut provides. First consider
the below text file as an example:
>cat example.txt
I want to learn linux, learn linux, learn linux.
Linux is the best
Linux forever
The cut command can be used to print characters in a line by specifying the position of the characters. To print the characters in
a line, use the -c option in cut command. The below cut command prints the fourth character in each line of the file. You can
also print more than one character at a time by specifying the character positions in a comma separated list.
>cut -c4 example.txt
You can print a range of characters in a line by specifying the start and end position of the characters. The below cut command
prints the characters from fourth position to the seventh position in each line:
>cut -c4-7 example.txt
You can use the cut command just as awk command to extract the fields in a file using a delimiter. The -d option in cut command
can be used to specify the delimiter and -f option is used to specify the field position. The below cut command uses comma as a
delimiter and prints the second and third field in each line:
Linux BASH Programming Cookbook 48 / 55
The below image illustrates the execution of the first 3 cut commands:
The below cut command prints the second field in each line by treating the space as delimiter. You can also print more than one
fields by specifying the position of the fields in a comma delimited list.
>cut -d’ ’ -f2 example.txt
You can print a range of fields by specifying the start and end position. The below cut command prints the first, second and third
fields:
>cut -d’ ’ -f1-3 example.txt
The /etc/passwd is a delimited file and the delimiter is a colon (:). The cut command to display the first field in /etc/passwd file
is the following:
>cut -d’:’ -f1 /etc/passwd
The below image illustrates the execution of the previous 3 cut commands:
Linux BASH Programming Cookbook 49 / 55
As we already shown in 5th example, a range of fields can be printed by specifying the start and end position. There is also a
possibility to omit the start position and declare only the last. The below cut command prints all fields from first to 3rd using
space as a delimiter:
>cut -d’ ’ -f-3 example.txt
You can also print all fields by omitting the last position and declaring only the start. The below cut command prints from second
field until the last one using space as delimiter:
>cut -d’ ’ -f2- example.txt
The cut command can be also be used to print only the lines that do not contain a certain delimiter by using the -s option. The
below cut command prints only the lines which contain the comma delimiter and fields from 2nd to last:
>cut -s -d’ ’ -f2- example.txt
Linux BASH Programming Cookbook 50 / 55
The below image illustrates the execution of the previous 3 cut commands:
The --complement option can be used with the cut command in order to print the inverted fields declared with the -f option. The
below cut command prints all except for the 2nd field from each line using space as a delimiter:
>cut --complement -d’ ’ -f2 example.txt
The previous cut commands which were used to print fields using a delimiter can be modified to have a different delimiter as
output, for example use space as delimiter to find fields but print the fields using comma as a delimiter. The below cut command
uses space as a delimiter and prints the second and third fields from each line but the output contains comma separated fields:
>cut --output-delimiter=, -d’ ’ -f2,3 example.txt
Similarly as printing characters using the cut command, you can also print bytes using the -b option. The below cut command
prints from first to fourth byte from each line:
>cut -b1-4 example.txt
The below image illustrates the execution of the last 3 cut commands:
Linux BASH Programming Cookbook 51 / 55
We tried to present some basic examples of using the cut command. Of course you may always use the man command to find the
full functionality of the linux cut command:
>man cut
Linux BASH Programming Cookbook 52 / 55
Chapter 10
cURL is an incredibly flexible and powerful tool data transferring tool, that supports a wide variety of protocols, being the HTTP
(and HTTPS) the most used. cURL library is available for many programming languages, but in this example we will see how to
use it from the command line.
For this tutorial, Mint 17.3 has been used.
10.1 Installation
The simplest way to use cURL is just executing it, and specifying a site:
curl <site>
For example
curl google.com
Which is not what we were expecting. This is because, by default, cURL doesn’t follow 3XX redirections. To make cURL
follow redirections, we have to pass the -L option:
Linux BASH Programming Cookbook 53 / 55
curl -L google.com
To save the HTTP response returned by cURL, we can always make a shell redirect with >, or use the -o option:
curl -o google.html -L google.com
To see more information, including the HTTP headers, we have available the -v (--verbose) option:
curl -v google.com
Which will show something similar to the following before the HTTP response:
* Rebuilt URL to: google.com/
* Hostname was NOT found in DNS cache
* Trying 130.206.193.53...
* Connected to google.com (130.206.193.53) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: google.com
> Accept: */*
>
< HTTP/1.1 302 Found
< Cache-Control: private
< Content-Type: text/html; charset=UTF-8
< Location: https://www.google.es/?gfe_rd=cr&ei=OulzV836N9Op8weYzoxY
< Content-Length: 256
< Date: Wed, 29 Jun 2016 15:28:58 GMT
<
# HTML
10.3 Requests
10.3.1 GET
Making GET request with cURL is so simple. Actually, is as same as making it in the browser. For example:
curl -o systemcodegeeks.html https://www.systemcodegeeks.com?s=linux
10.3.2 POST
To make a POST request, the usage is slightly different. The syntax is the following:
curl -d "field1=value1&field2=value2&fieldN=valueN" <site>
So, for making a search as the one done above, but supposing that the form method is POST, would be:
curl -d "s=linux" systemcodegeeks.com -o systemcodegeeks.html
Linux BASH Programming Cookbook 54 / 55
In this case, we have to specify the -F option for the file. And, the leading @ before the path to the file is necessary.
For making a POST request that combines both files and normal data, the data has to bet set also with -F, and not with -d. This
is because the forms for file uploads sets the data encoding to -multipart/form-data, and this is what -F option does;
whereas -d option sets the encoding to application/x-www-form-urlencoded. And all the data in a form has to be
encoded under the same encoding. So, we have to specify also the data with -F option:
curl -F "field=value" -F "file=@/path/to/file.txt" awebsite.com/uploadfile
PUT and DELETE are considered custom-methods. These requests are mostly used in CRUDs (Create, Read, Update,
Delete), in RESTful services. To specify these commands, we have to use -X option.
For example:
curl -X PUT -d "data=stuff" https://myserver.com/rows/1
curl -X DELETE https://myserver.com/rows/1
For adding extra headers to a request, we just have to use the -H option (--header), specifying the header, and the value:
curl --header "X-ExtraHeader: myheader" https://myserver.com
10.4 FTP
We must take into account that, unless SSL is being used, the data will travel in plain text. If SSL is available, ftps should be
use, instead of ftp.
We can upload files pretty simply, just specifying the local file with -T option:
curl -T file.txt ftps://username:password@myftp.com/path
Downloading files from FTP server is the same as downloading a simple HTML:
curl ftps://username:password@myftp.com/path/file.txt -o file.txt
Apart from the common uses of cURL, let’s see other features that may result useful in some occasions.
Linux BASH Programming Cookbook 55 / 55
With cURL is also possible to make HTTP authentication (that login prompts shown by the browser, not the authentication
forms). For that, we have to use the -u (--user) option and specify the credentials:
curl -u username:password https://mylogin.com
You will probably ever have encountered a site for which the browser shows a SSL certificate error, that it can be caused because
it’s expired, because the certificate authority is not trusted by the browser, or any other reason. If we want to ignore the warning
and access the site, we have to give explicit consent to the browser. By default, cURL does not accept the connections with SSL
errors, but we can make it ignore them with -k (--insecure) option:
curl -k https://insecure-site.com
10.5.3 Cookies
Setting custom cookies with cURL is as easy as specifying them in name=value format, with -b (--cookie) option:
curl -b "mycookie=value" systemcodegeeks.com
And, of course, we can save the cookies to a file, with -c (--cookie-jar) option:
curl -c cookies.txt systemcodegeeks.com
Yes, cURL also allows to make requests through proxies. We just have to use the -x option, specifying the proxy:
curl -x https://aproxy.com systemcodegeeks.com
If the proxy server requires authentication, we have to specify as same as with HTTP authentication, but with --proxy-user
option:
curl -x https://aproxy.com --proxy-user username:password systemcodegeeks.com
This is nice. We can make cURL download a file only if it has suffered modifications after the specified time, with -z ( --
time-cond ) option:
curl -z 25 -Jun-16 systemcodegeeks.com
This feature can be specially useful for automating the task of having up-to-date documentation or software, for example.
10.6 Summary
This example has shown how to use cURL, from its simplest uses, which are downloading pages or making simple requests,
to more advanced topics (which are actually easy with cURL), such us FTP connection, setting and saving cookies, or using
proxies.