Once you have your first Red Hat Enterprise Linux (RHEL) system running, you want to start using it, practicing, and getting comfortable with it. In this chapter, we will review the basics of logging into the system, navigating through it, and getting to know the basics in terms of its administration.
The set of commands and practices described in this chapter will be used on many occasions when managing systems, so it is important to study them with care.
The following topics will be covered in this chapter:
Login is the process during which a user identifies themselves in the system – usually, by providing a username and password, a couple of pieces of information often referred to as credentials.
The system can be accessed in many ways. The initial case for this, which we are covering here, is how a user accesses it when they install a physical machine (such as a laptop) or via the virtualization software interface. In this case, we are accessing the system through a console.
During installation, the user was created with an assigned password, and no graphical interface was installed. We will access the system in this case via its text console. The first thing we are going to do is to log in to the system using it. Once we start the machine and the boot process is completed, we will enter, by default, the multi-user text mode environment in which we are being requested to provide our login:
Figure 3.1 – The login process and username request
The blinking cursor will let us know that we are ready to enter our username, in this case, user, and then press Enter. A line requesting the password will appear:
Figure 3.2 – The login process and password request
We may now type the user’s password to complete the login and, by pressing Enter on your keyboard, start a session. Note that no characters will be displayed on the screen when typing the password to avoid eavesdropping. The following screenshot shows the session running:
Figure 3.3 – The completed login process and the session running
Now, we are fully logged in to the system with the credentials for a user called user. This will define what we can do in the system, which files we can access, and even how much disk space we are assigned.
The console can have more than one session. To make that possible, we have different terminals through which we can log in. The default terminal can be reached by simultaneously pressing the Ctrl + Alt + F1 keys. In our case, nothing will happen, as we are already in that terminal. We could move to the second terminal by pressing Ctrl + Alt + F2, to the third one by pressing Ctrl + Alt + F3, and so on for the rest of the terminals (by default, six are allocated). This way, we can run different commands in different terminals.
Regular users will not be able to make changes to the system, such as creating new users or adding new software to the whole system. To do so, we need a user with administrative privileges and for that, the default user is root. This user always exists in the system and its identifier – the User Id (UID) – has the value 0.
In the previous installation, we configured the root password, making the account accessible through the console. To use it by logging in to the system, we only need to type the user root into one of the terminals shown right next to the login, then hit Enter, and then provide its password, which won’t be displayed. This way, we will access the system as the administrator, root:
Figure 3.4 – The completed login process for root
Important Note
Above the login prompt, there is a message suggesting how the activation of the web console (cockpit) can be done – the cockpit is a set of tools that enables web management for the system. The cockpit is covered in Chapter 4, Tools for Regular Operations.
The command line that appears once we have logged in and are waiting for our commands to be typed and run is called the command prompt.
In its default configuration, it will show the username and hostname between brackets to let us know with which user we are working. Next, we see the path, in this case, ~, which is the shortcut for the user’s home directory (in other words, /home/user for user, and /root for root).
The last part and, probably the most important one, is the symbol before the prompt:
Important Note
Be careful when using a prompt with the # sign, as you will be running as an administrator and the system will likely not stop you from damaging it.
Once we have identified ourselves within the system, we are logged in and have a running session. It is time to learn how to change from one user to the other in the following section.
As we have entered a multi-user system, it is logical to think that we will be able to change between users. Even when this can be done easily by opening a session for each, sometimes we want to act as several users within one session.
To do so, we can use the su tool. The name of the tool is usually referred to as Substitute User.
Let’s use that last session, in which we logged in as root, and turn ourselves into user.
Before doing so, we can always ask which user we are logged in as by running the whoami command:
[@rhel-instance ~]# whoami
root
Now, we can make the change from root to user:
[root@rhel-instance ~]# su user
[user@rhel-instance root]$ whoami
user
Now, we have a session as user. We can finish this session by using the exit command:
[user@rhel-instance root]$ exit
exit
[root@rhel-instance ~]# whoami
root
As you may have seen, when we are logged in as root, we can act as any user without knowing its password. But how can we impersonate root? We can do so by running the su command and specifying the root user. In this case, the root user’s password will be requested:
[user@rhel-instance ~]$ su root
Password:
[@rhel-instance user]# whoami
root
As root is the user with the ID 0 and the most important one, when running su without specifying the user we want to turn into, it will default to turning us into root:
[user@rhel-instance ~]$ su
Password:
[root@rhel-instance user]# whoami
root
Each user can define several options in their own environment, such as, for example, their preferred editor. If we want to fully impersonate the other user and take their preferences (or environment variables, as they are referred to on many occasions), we can do so by adding - after the su command:
[user@rhel-instance ~]$ su -
Password:
Last login: mar feb 15 04:57:29 CET 2022 on pts/0
[root@rhel-instance ~]#
We can also switch from root to user:
[root@rhel-instance ~]# su - user
Last login: Tue Feb 15 04:53:02 CET 2022 from 192.168.122.1 on pts/0
As you can observe, it behaves as if a new login was done, but within the same session. Now, let’s move on to managing the permissions for the different users in the system, as addressed in the following section.
Multi-user environments are defined by being able to handle more than one user simultaneously. But to be able to administer the system resources, two capabilities help with the tasks:
Each user has a primary group.
By default, a group is created for each user and assigned to it as a primary with the same name as the username.
Standard Linux (and UNIX or POSIX) permissions include user, group, and others (ugo).
The whole system comes with a set of permissions assigned by default to each file and directory. Be careful when changing them.
There is a certain principle in UNIX that Linux has inherited: everything is a file. Even when there may be some corner cases to this principle, it remains true on almost any occasion. It means that a disk is represented as a file in the system (in other words, such as /dev/sdb mentioned in the installation), a process can be represented as a file (under /proc), and many other components in the system are also represented as files.
This means that, when assigning permissions to files, we can also assign permissions to many other components and capabilities implemented by them by virtue of the fact that, in Linux, everything is represented as a file.
Tip
The Portable Operating System Interface (POSIX) is a family of standards specified by the IEEE Computer Society: https://en.wikipedia.org/wiki/POSIX.
Users are a way of providing security limits to people as well as programs running in a system. There are three types of users:
Users have a number called the UID that the system uses to internally identify each one of them.
We previously used the whoami command to reveal which user we were working with, but to get more information here, we will use the id command:
[user@rhel-instance ~]$ id
uid=1000(user) gid=1000(user) groups=1000(user),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
We can also check the information related to other user accounts in the system, even to get info about root:
[user@rhel-instance ~]$ id root
uid=0(root) gid=0(root) groups=0(root)
Now, let’s take a look at the information we have received for user by running id:
ID-related data is stored in the system in the /etc/passwd file. Please note that this file is very sensitive and is better managed by using the tools related to it. If we want to edit it, we will do so by using vipw, a tool that will ensure (among other things) that only one admin is editing the file at any one time. The /etc/passwd file contains the info of each user per line. This is the line for user:
user:x:1000:1000:user:/home/user:/bin/bash
Each field is separated by a colon, :, in each line. Let’s review what they mean:
Groups are a way of assigning certain permissions to a subset of users in a dynamic way. As an example, let’s imagine a scenario where we have a finance team. We can create the finance group and provide permission to access, read, and write the /srv/finance directory. When the finance team has a new hire, to provide them with access to that folder, we only need to add the user assigned to this person to the finance group (this also works if someone leaves the team – we will only have to remove their account from the finance group).
Groups have a number called the GID that the system uses to identify them internally.
The data for groups is stored in the system in the /etc/group file. To edit this file in a way that ensures consistency and avoids corruption, we have to use the vigr tool. The file contains one group per line with different fields separated by a colon (:). Let’s take a look at the line for the wheel group:
wheel:x:10:user
Let’s review what each field means:
The types of groups are as follows:
To review file permissions, we are going to log in to the system as root. We will use the ls command to list files and we will review the permissions associated with them. We will learn more about how to change permissions in Chapter 5, Securing Systems with Users, Groups, and Permissions.
Once logged in to the system as root, we can run the ls command:
[root@rhel-instance ~]# ls
anaconda-ks.cfg
This shows the files present in the root user home directory, represented by ~. In this case, it shows the kickstart file created by Anaconda that we reviewed in the previous chapter.
We can get the long version of the list by appending the -l option to ls:
[root@rhel-instance ~]# ls -l
total 4
-rw-------. 1 root root 1106 Feb 18 19:45 anaconda-ks.cfg
We see the following in the output:
The structure of the permissions can be seen in the following diagram:
Figure 3.5 – The permissions structure for Linux
Let’s discuss the preceding structure:
The next three characters, rw-, are the permissions for the owner:
The next three characters, ---, are for the group permissions and work the same way as the owner permission. In this case, no group access is granted.
The final three characters, ---, are the permissions for others, which means users or groups do not show as the ones assigned to the file:
When we list a directory (referred to in other systems as a folder), the output will show the contents of the directory itself. We can list the info for the directory itself with the -d option. Let’s now take a look at /etc, the directory that stores the system-wide configuration:
[root@rhel-instance ~]# ls -l -d /etc
drwxr-xr-x. 103 root root 8192 Feb 18 18:03 /etc
As you can see, it’s quite easy to obtain information about files and directories in the system. Let’s now learn more about the command line and how to navigate the filesystem easily in the following section.
As we have seen before, once we log in to the system, we have access to the command line. It’s important to navigate the command line and the filesystem well to feel comfortable in the environment and make the most of it.
The command line is provided by a program also known as an interpreter or shell. It will behave differently depending on which shell we use, but in this section, we will cover the most widespread shell used in Linux and the one provided by default in RHEL – bash.
A simple trick to know which shell you are using is to run the following command:
[root@rhel-instance ~]# echo $SHELL
/bin/bash
The echo command will show the content of whatever we give to it on the screen. Some content needs to be substituted or interpreted, such as environment variables. The content to be substituted starts with the $ symbol. In this case, we are telling the system to use the echo function on (and therefore, echo) the content of the SHELL variable. Let’s use it for other variables:
[root@rhel-instance ~]# echo $USER
root
[root@rhel-instance ~]# echo $HOME
/root
These are environment variables that can be customized for every user. Let’s now check these for a different user:
[root@rhel-instance ~]# su - user
Last login: Wed Feb 16 19:03:32 CET 2022 from 192.168.122.1 on pts/0
[user@rhel-instance ~]$ echo $USER
user
[user@rhel-instance ~]$ echo $HOME
/home/user
As you can see, you can always refer to $USER and it will be substituted with the current user, or to $HOME and it will be substituted by the directory dedicated to the user, also known as the home directory.
These are some of the most common and important environment variables:
Table 3.1 – Common environment variables
The ~/.bashrc file is the one that should be edited to change these values for the current user.
Important Note
Files starting with a dot (.) are hidden files – to see them, you can use the ls -a command.
Now, it’s time to move into the directory tree of the system. In Linux and Unix (macOS is a Unix-like system), there are no drive letters, but a single directory tree that starts with the root directory, represented by /. The rest of the content of the system will hang from that folder and any other accessible disk or device will be assigned an accessible directory.
Important Note
The root directory and the home directory for the root user are two different things. The root user is assigned the home directory, /root, by default, whereas the root directory is the mother of all directories in the system and is represented by /.
We can see which directory we are in by running the pwd command:
[user@rhel-instance ~]$ pwd
/home/user
We can change the directory by using the cd command:
[user@rhel-instance ~]$ cd /var/tmp
/var/tmp
As you already know, there is a shortcut for the home directory of the current user, ~. We can use this shortcut to go to it:
[user@rhel-instance tmp]$ cd ~
[user@rhel-instance ~]$ pwd
/home/user
Some shortcuts for directories include the following:
More details on managing files and directories in Linux and RHEL are available in the Listing, creating, copying, and moving files, directories, links, and hard links section.
Shortcuts are a faster way to reach commonly used directories or relative references to the current working directory. However, bash includes some capabilities to reach other directories in a fast way, which is called auto-completion. It relies on the Tab key (the one with two opposing arrows at the very left of your keyboard, right above Caps Lock).
When reaching a folder or a file, we can hit Tab to complete its name. For example, if we want to go to the /etc/NetworkManager folder, we type the following:
[user@rhel-instance ~]$ cd /et
Then, when we hit the Tab key, this will auto-complete it to /etc/, even adding the final forward slash (/), as it is a directory:
[user@rhel-instance ~]$ cd /etc/
Now, we type in the first letter of the directory we want to go to, NetworkManager, which is N:
[user@rhel-instance ~]$ cd /etc/N
Then, when we hit the Tab key, this will auto-complete it to /etc/NetworkManager/:
[user@rhel-instance ~]# cd /etc/NetworkManager/
Now, we can hit Enter and go there.
If we press Tab + Tab (pressing Tab twice during complete), this will show a list of available targets to complete – for example, see the following:
root/ run/
It can also be used to complete commands. We can type a letter, for example, h, hit Tab + Tab, and this will show all the commands starting with h:
[user@rhel-instance ~]# h
halt hardlink hash h dparm head help hexdump history hostid hostname hostnamectl hwclock
This capability can be extended to help complete other parts of our commands by installing the bash-completion package:
[user@rhel-instance ~]# yum install bash-completion –y
Tip
A good practice when installing a system is to install bash-completion and also create or update the manuals database with the mandb command to get the latest manuals available using the man <command> command.
There is a way to recover the last commands run, which is referred to as history, in case you want to re-run them. Just press the up arrow key (the one with an arrow pointing up) and the previous commands will appear onscreen.
If there are too many commands in your history, you can search through them quickly by running the history command:
[user@rhel-instance ~]$ history
1 su root
2 su
3 su -
4 id
5 id root
6 grep user /etc/passwd
7 echo $USER
8 echo $HOME
9 declare
10 echo $SHELL
11 echo EDITOR
12 echo $EDITOR
13 grep wheel /etc/gro
14 grep wheel /etc/group
15 cat /etc/group
16 grep nobody /etc/group /etc/passwd
You can run any of those commands again by using the ! command. Just run ! with the number of the command and it will run again:
[user@rhel-instance ~]$ !5
id root
uid=0(root) gid=0(root) groups=0(root)
Tip
The !! command will run the very last command again, no matter which number.
Now, it is time to enjoy your superfast command line. Let’s learn more about the structure of directories in Linux, to know where to go to find things, in the following section.
Linux has a standard, maintained by the Linux Foundation, that defines the filesystem hierarchy used in almost every Linux distribution, including RHEL. This standard is known as the FHS, or the Filesystem Hierarchy Standard. Let’s review the most important folders in the standard and the system itself here:
Table 3.2 – The most important folders in the filesystem
Tip
Previous versions of RHEL used to have /bin for the essential binaries and /usr/bin for the non-essential ones. Now, the content of both resides in /usr/bin. They also used /var/lock and /var/run for what is running in /run. In addition, they used to have /lib for the essential libraries and /usr/lib for the non-essential ones, which were consolidated into a single directory, /usr/lib. And last but not least, /sbin is the directory for the essential superuser binaries, and /usr/sbin is the directory for the non-essential ones, merged under /usr/sbin.
When partitioning, we may well be asking ourselves, where does the disk space go?
These are the allocation values for a minimal installation of RHEL 9 and the recommendations:
Table 3.3 – The allocation values for a minimal installation of RHEL 9
It’s important to become familiar with the main directories in the system to make the best of them. It is recommended to navigate through the different system directories and look at what’s in them to become comfortable with the structure. In the following section, we will look at how to perform redirections on the command line to learn more about command and file interaction.
We have already run several commands to ascertain information about the system, such as listing files with ls, and we have got some information, or the output, from the running command, including, for example, filenames and file sizes. That information (or output) can be useful, and we want to be able to work with it, store it, and manage it properly.
When talking about command output and also input, there are three sources or targets for them that need to be understood:
We will cover these in the following paragraphs to understand them better.
The way that the command input and output are used is defined by the following operators:
To better understand these, we will go through several examples in this section and the following one.
Let’s get a list of files and put it in a file. First, we list the files in /var, using the -m option to separate entries with commas:
[root@rhel-instance ~]# ls -m /var/
account, adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock, log, mail, nis, opt, preserve, run, spool, tmp, yp
Now, we run the command again, redirecting the output to the /root/var-files.txt file:
[root@rhel-instance ~]# ls –m /var/ > /root/var-files.txt
[root@rhel-instance ~]#
As we can see, no output is shown on screen, but we will be able to find the new file in the current working directory – in this case, /root, the newly created file:
[root@rhel-instance ~]# ls /root
anaconda-ks.cfg var-files.txt
To see the content of the file on screen, we use the cat command, intended to concatenate the output for several files, but regularly used for this purpose:
[root@rhel-instance ~]# cat var-files.txt
account adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock, log, mail, nis, opt, preserve, run, spool, tmp, yp
We can also add to this file the content of /var/lib. First, we can list it:
[root@rhel-instance ~]# ls -m /var/lib/
alternatives, authselect, chrony, dbus, dhclient, dnf, games, initramfs, logrotate, misc, NetworkManager, os-prober, plymouth, polkit-1, portables, private, rhsm, rpm, rpm-state, rsyslog, selinux, sss, systemd, tpm, tuned, unbound
Now, to append this content to the /root/var-files.txt file, we use the >> operator:
[root@rhel-instance ~]# ls -m /var/lib/ >> var-files.txt
[root@rhel-instance ~]# cat var-files.txt
account, adm, cache, crash, db, empty, ftp, games, gopher, kerberos, lib, local, lock, log, mail, nis, opt, preserve, run, spool, tmp, yp
alternatives, authselect, chrony, cni, containers, dnf, fprint, games, initramfs, iscsi, kdump, logrotate, misc, mlocate, NetworkManager, os-prober, PackageKit, plymouth, polkit-1, private, rhsm, rpm, rpm-state, rsyslog, samba, selinux, setroubleshoot, smartmontools, sss, systemd, tpm2-tss, udisks2, unbound, xfsdump
The /root/var-files.txt file now contains both the comma-separated list for /var and for /var/lib.
Now, we can try to list a non-existing directory to see an error being printed:
[root@rhel-instance ~]# ls -m /non
ls: cannot access '/non': No such file or directory
The output we see is an error and is treated differently by the system than regular messages. We can try to redirect the output to a file:
[root@rhel-instance ~]# ls -m /non > non-listing.txt
ls: cannot access '/non': No such file or directory
[root@rhel-instance ~]# cat non-listing.txt
[root@rhel-instance ~]#
We can see that using the standard redirect, with a command providing an error message, will show the error message (via STDERR) onscreen and create an empty file. This is because the file contains the output of the common information messages that are shown via STDOUT. We can still capture the output of the error, redirecting STDERR, by using 2>:
[root@rhel-instance ~]# ls -m/non 2> /root/error.txt
[root@rhel-instance ~]# cat /root/error.txt
ls: cannot access '/non': No such file or directory
Now, we can redirect the standard output and the error output independently.
Now, we want to count the number of files and directories in /var. For that, we are going to use the wc command, which stands for word count, with the -w option to only focus on counting words. To do so, we will redirect the output of ls to it by using a pipe represented by |:
[root@rhel-instance ~]# ls -m /var/ | wc -w
21
We can also use it to count the entries in /etc:
[root@rhel-instance ~]# ls -m /etc/ | wc -w
199
Pipes, |, are great for reusing the output of one command and sending it to another command to process that output. Now, we know more about using the more common operators to redirect input and output. There are several ways to process that output and we will see more examples in the following section.
The grep command is heavily used (and commonly mistyped) in system administration. It helps when finding a pattern in a line, whether in a file or via standard input (STDIN).
Let’s do a recursive search of the files in /usr with find and put it in /root/usr-files.txt:
[root@rhel-instance ~]# find /usr/ > /root/usr-files.txt
[root@rhel-instance ~]# ls -lh usr-files.txt
-rw-r--r--. 1 root root 2,1M Feb 18 12:38 usr-files.txt
As you can see, it’s a 2.1 MB file and it isn’t easy to go through. There is a utility in the system called gzip and we want to know which files in /usr contain the gzip pattern. To do so, we can run the following command:
[root@rhel-instance ~]# grep gzip usr-files.txt
/usr/bin/gzip
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.opt-2.pyc
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.opt-1.pyc
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.pyc
/usr/lib64/python3.9/gzip.py
/usr/share/licenses/gzip
/usr/share/licenses/gzip/COPYING
/usr/share/licenses/gzip/fdl-1.3.txt
/usr/share/man/man1/gzip.1.gz
/usr/share/doc/gzip
/usr/share/doc/gzip/AUTHORS
/usr/share/doc/gzip/ChangeLog
/usr/share/doc/gzip/NEWS
/usr/share/doc/gzip/README
/usr/share/doc/gzip/THANKS
/usr/share/doc/gzip/TODO
/usr/share/info/gzip.info.gz
/usr/share/mime/application/gzip.xml
As you can see, we have found all the files with gzip under the /usr directory by creating a file with all the content and searching through it with grep. Could we do the same without creating the file? We sure could – by using a pipe. We can redirect the output of find to grep and get the same output:
[root@rhel-instance ~]# find /usr/ | grep gzip
/usr/bin/gzip
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.opt-2.pyc
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.opt-1.pyc
/usr/lib64/python3.9/__pycache__/gzip.cpython-39.pyc
/usr/lib64/python3.9/gzip.py
/usr/share/licenses/gzip
/usr/share/licenses/gzip/COPYING
/usr/share/licenses/gzip/fdl-1.3.txt
/usr/share/man/man1/gzip.1.gz
/usr/share/doc/gzip
/usr/share/doc/gzip/AUTHORS
/usr/share/doc/gzip/ChangeLog
/usr/share/doc/gzip/NEWS
/usr/share/doc/gzip/README
/usr/share/doc/gzip/THANKS
/usr/share/doc/gzip/TODO
/usr/share/info/gzip.info.gz
/usr/share/mime/application/gzip.xml
In this command, the standard output from find was sent to grep to process it. We can even count the number of instances of files with wc, but this time, using the -l option to count the lines:
[root@rhel-instance ~]# find /usr/ | grep gzip | wc -l
18
We have now concatenated two pipes, one to filter the output and another to count it. We will find ourselves doing this kind of plumbing often when searching for and finding information in the system.
Some very common options for grep are as follows:
There is also a way to also filter columns in the output provided. Let’s say we have a list of files in our home directory and we want to see its size. We run the following command:
[root@rhel-instance ~]# ls -l
total 1888
-rw-------. 1 root root 1393 Feb 18 19:45 anaconda-ks.cfg
-rw-r--r--. 1 root root 52 Feb 16 12:17 error.txt
-rw-r--r--. 1 root root 0 Feb 16 12:08 non-listing.txt
-rw-r--r--. 1 root root 1917837 Feb 16 12:40 usr-files.txt
-rw-r--r--. 1 root root 360 Feb 16 12:12 var-files.txt
Let’s say we only want the size, which is the fifth column, of the content that has files in its name. We can use awk for that:
[root@rhel-instance ~]# ls -l | grep files | awk '{ print $5}'
1917837
360
The awk tool will help us to filter according to the correct column. It is very useful for finding identifiers in processes or for getting a specific list of data from a long output.
Tip
Consider that awk is super powerful for processing output and that we will use the minimal capability for it.
We could replace the separator with -F and get a list of available users in the system:
[root@rhel-instance ~]# awk -F: '{ print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
operator
games
ftp
nobody
dbus
systemd-coredump
systemd-resolve
tss
polkitd
unbound
sssd
chrony
sshd
rngd
user
The awk and grep tools are very common processing tools in the life of a Linux sysadmin, and it is important to understand them well to manage the output provided by the system. We have applied the base knowledge to filter the output received by row and column. Let’s now move on to how to manage files in a system so that we can better handle the stored output we have just generated.
It is important to know how to manage files and directories in a system from the command line. It will serve as the basis for managing and copying important data, such as configuration files or data files.
Let’s start by creating a directory to keep some working files. We can do so by running mkdir, short for “make directory”:
[user@rhel-instance ~]$ mkdir mydir
total 0
drwxrwxr-x. 2 user user 6 Feb 13 19:53 mydir
Folders can be deleted with the rmdir command, short for “remove directory”:
[user@rhel-instance ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Feb 13 19:53 mydir
[user@rhel-instance ~]$ mkdir deleteme
[user@rhel-instance ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Feb 13 20:15 deleteme
drwxrwxr-x. 2 user user 6 Feb 13 19:53 mydir
[user@rhel-instance ~]$ rmdir deleteme
[user@rhel-instance ~]$ ls -l
total 0
drwxrwxr-x. 2 user user 6 Feb 13 19:53 mydir
However, rmdir will only delete empty directories:
[user@rhel-instance ~]$ ls /etc/ > ~/mydir/etc-files.txt
[user@rhel-instance ~]$ rmdir mydir
rmdir: failed to remove 'mydir': Directory not empty
How can we delete a directory and all the other files and directories it contains using the remove (rm) command? First, let’s just create and remove a single file, var-files.txt:
[user@rhel-instance ~]$ ls /var/ > ~/var-files.txt
[user@rhel-instance ~]$ ls -l var-files.txt
-rw-rw-r--. 1 user user 109 Feb 13 15:31 var-files.txt
[user@rhel-instance ~]$ rm var-files.txt
[user@rhel-instance ~]$ ls -l var-files.txt
ls: cannot access 'var-files.txt': No such file or directory
To remove a full directory branch, including its contents, we may use the -r option, short for “recursive”:
[user@rhel-instance ~]$ rm -r mydir/
[user@rhel-instance ~]$ ls -l
total 0
Important Note
Be very careful when using recursive mode to delete things, as there is neither a recovery command for it nor a trash bin to keep files that have been removed in the command line.
Let’s take a look at the review table:
Table 3.4 – The directory commands
Now that we know how to create and delete directories in a Linux system, let’s start copying and moving content.
Now, let’s copy some files to play with them using the cp (which stands for copy) command. We may get some powerful awk examples copied to our home directory:
[user@rhel-instance ~]$ mkdir myawk
[user@rhel-instance ~]$ cp /usr/share/awk/* myawk/
[user@rhel-instance ~]$ ls myawk/ | wc -l
27
To copy more than one file at the same time, we have used globbing with the * sign. This works so that by specifying the files one by one, we can just type * for everything. We can also type the initial characters and then *, so let’s try this by copying some more files using globbing:
[user@rhel-instance ~]$ mkdir mysystemd
[user@rhel-instance ~]$ cp /usr/share/doc/systemd/* mysystemd/
[user@rhel-instance ~]$ cd mysystemd/
[user@rhel-instance mysystemd]$ ls
20-yama-ptrace.conf CODING_STYLE DISTRO_PORTING ENVIRONMENT.md GVARIANT-SERIALIZATION HACKING NEWS README TRANSIENT-SETTINGS.md TRANSLATORS UIDS-GIDS.md
You will see that running ls TR* only shows files that start with TR:
[user@rhel-instance mysystemd]$ ls TR*
TRANSIENT-SETTINGS.md TRANSLATORS
It will work the same way with the file ending:
[user@rhel-instance mysystemd]$ ls *.md
ENVIRONMENT.md TRANSIENT-SETTINGS.md UIDS-GIDS.md
As you can see, it only shows files ending in .md.
We can copy a full branch of files and directories with the recursive option for cp, which is -r:
[user@rhel-instance mysystemd]$ cd ~
[user@rhel-instance ~]$ mkdir myauthselect
[user@rhel-instance ~]$ cp -r /usr/share/authselect/* myauthselect
[user@rhel-instance ~]$ ls myauthselect/default/
minimal sssd winbind
The recursive option is very useful for copying complete branches. We could also move directories or files easily using the mv command. Let’s put all our new directories together into a newly created directory called docs:
[user@rhel-instance ~]$ mkdir docs
[user@rhel-instance ~]$ mv my* docs/
[user@rhel-instance ~]$ ls docs/
myauthselect myawk mysystemd
You can see that with mv, you do not need to use the recursive option to manage a full branch of files and directories. It can also be used to rename files or directories:
[user@rhel-instance ~]$ cd docs/mysystemd/
[user@rhel-instance mysystemd]$ ls
20-yama-ptrace.conf CODING_STYLE DISTRO_PORTING ENVIRONMENT.md GVARIANT-SERIALIZATION HACKING NEWS README TRANSIENT-SETTINGS.md TRANSLATORS UIDS-GIDS.md
[user@rhel-instance mysystemd]$ ls -l NEWS
-rw-r--r--. 1 user user 451192 Feb 16 19:59 NEWS
[user@rhel-instance mysystemd]$ mv NEWS mynews
[user@rhel-instance mysystemd]$ ls -l NEWS
ls: cannot access 'NEWS': No such file or directory
[user@rhel-instance mysystemd]$ ls -l mynews
-rw-r--r--. 1 user user 451192 Feb 16 19:59 mynews
There is a special command for creating empty files, which is touch:
[user@rhel-instance mysystemd]$ cd ~
[user@rhel-instance ~]$ ls -l docs/
total 4
drawer-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
drwxrwxr-x. 2 user user 238 Feb 16 20:21 mysystemd
[user@rhel-instance ~]$ touch docs/mytouch
[user@rhel-instance ~]$ ls -l docs/
total 4
drwxrwxr-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
drwxrwxr-x. 2 user user 238 Feb 16 20:21 mysystemd
-rw-rw-r--. 1 user user 0 Feb 16 20:27 mytouch
When applied to an existing file or folder, it will update its access time to the current one:
[user@rhel-instance ~]$ touch docs/mysystemd
[user@rhel-instance ~]$ ls -l docs/
total 4
drwxrwxr-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
drwxrwxr-x. 2 user user 238 Feb 16 20:28 mysystemd
-rw-rw-r--. 1 user user 0 Feb 16 20:27 mytouch
Let’s check the review table:
Table 3.5 – Copying and moving commands
Now we know how to copy, delete, rename, and move files and directories, even full directory branches. Let’s now take a look at a different way to work with them – links.
We can have the same file in two places using links. There are two types of links:
Both are created using the ln (which stands for link) utility.
Let’s now create hard links:
[user@rhel-instance ~]$ cd docs/
[user@rhel-instance docs]$ ln mysystemd/README MYREADME
[user@rhel-instance docs]$ ls -l
total 20
drwxrwxr-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
-rw-r--r--. 2 user user 13826 Feb 16 20:59 MYREADME
drwxrwxr-x. 2 user user 238 Feb 16 20:28 mysystemd
-rw-rw-r--. 1 user user 0 Feb 16 20:27 mytouch
[user@rhel-instance docs]$ ln MYREADME MYREADME2
[user@rhel-instance docs]$ ls -l
total 36
drwxrwxr-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
-rw-r--r--. 3 user user 13831 Feb 16 20:32 MYREADME
-rw-r--r--. 3 user user 13831 Feb 16 20:32 MYREADME2
drwxrwxr-x. 2 user user 238 Feb 16 20:28 mysystemd
-rw-rw-r--. 1 user user 0 Feb 16 20:27 mytouch
drwxrwxr-x. 2 user user 6 Feb 16 20:35 test
Check the increasing number of references to the file (in bold in the previous example).
Now, let’s create a symbolic link to a directory with ln -s (with s for symbolic):
[user@rhel-instance docs]$ ln -s mysystemd mysystemdlink
[user@rhel-instance docs]$ ls -l
total 36
drwxrwxr-x. 4 user user 35 Feb 16 20:08 myauthselect
drwxrwxr-x. 2 user user 4096 Feb 16 19:51 myawk
-rw-r--r--. 3 user user 13831 Feb 16 20:32 MYREADME
-rw-r--r--. 3 user user 13831 Feb 16 20:32 MYREADME2
drwxrwxr-x. 2 user user 238 Feb 16 20:28 mysystemd
lrwxrwxrwx. 1 user user 9 Feb 16 20:40 mysystemdlink -> mysystemd
-rw-rw-r--. 1 user user 0 Feb 16 20:27 mytouch
drwxrwxr-x. 2 user user 6 Feb 16 20:35 test
Check how the symbolic link created is treated as a different type when listing it, as it starts with l for link (in bold in the previous example) instead of d for directory (also in bold in the previous example).
Tip
When in doubt about whether to use a hard link or a symbolic link, use the symbolic link as the default choice.
Let’s check the review table:
Table 3.6 – Link commands
As you can see, creating links and symbolic links is super simple and can help us access the same file or directory from different locations. In the following section, we will cover how to pack and compress a set of files and directories.
Sometimes, we want to pack a full directory (including files) into a single file for backup purposes or to simply share it more easily. The command that can help aggregate files into one is tar.
First, we need to install tar:
[root@rhel-instance ~]# yum install tar -y
We can try by creating (as root) a backup of the /etc directory branch:
[root@rhel-instance ~]# tar -cf etc-backup.tar /etc
tar: Removing leading '/' from member names
[root@rhel-instance ~]# ls -lh etc-backup.tar
-rw-r--r--. 1 root root 20M Feb 17 20:08 etc-backup.tar
Let's check the options used:
We can try to unpack it:
[root@rhel-instance ~]# mkdir tmp
[root@rhel-instance ~]# cd tmp/
[root@rhel-instance tmp]# tar -xf ../etc-backup.tar
[root@rhel-instance tmp]# ls
etc
Let’s check the new options used:
Observe that we created a directory called tmp to work on and that we pointed to the parent directory of tmp by using the .. shortcut (which refers to the parent directory of the current working directory).
Let’s use gzip to compress a file. We can copy /etc/services and compress it:
[root@rhel-instance tmp]# cp /etc/services .
[root@rhel-instance tmp]# ls -lh services
-rw-r--r--. 1 root root 677K Jun 23 2020 services
[root@rhel-instance tmp]# gzip services
[root@rhel-instance tmp]# ls -lh services.gz
-rw-r--r--. 1 root root 140K Feb 17 20:16 services.gz
Please note that when using gzip, this will compress the specified file, adding the .gz extension to it, and the original file will not be kept. Also, be aware that the newly created file is one fifth of the size of the original file.
To recover it, we can run gunzip:
-rw-r--r--. 1 root root 140K Feb 17 20:16 services.gz
[root@rhel-instance tmp]# gunzip services.gz
[root@rhel-instance tmp]# ls -lh services
-rw-r--r--. 1 root root 677K Feb 17 20:16 services
Now, we can combine the two of them, packing and compressing them:
[root@rhel-instance ~]# tar cf etc-backup.tar /etc/
tar: Removing leading '/' from member names
[root@rhel-instance ~]# ls -lh etc-backup.tar
-rw-r--r--. 1 root root 20M Feb 17 20:08 etc-backup.tar
[root@rhel-instance ~]# gzip etc-backup.tar
[root@rhel-instance ~]# ls etc-backup.tar.gz
etc-backup.tar.gz
[root@rhel-instance ~]# ls -lh etc-backup.tar.gz
-rw-r--r--. 1 root root 4,9M Feb 17 20:20 etc-backup.tar.gz
This way, we pack and compress in two steps.
The tar command is smart enough to be able to perform packing and compression in a single step:
[root@rhel-instance ~]# rm -f etc-backup.tar.gz
[root@rhel-instance ~]# tar -czf etc-backup.tar.gz /etc/
tar: Removing leading '/' from member names
[root@rhel-instance ~]# ls -lh etc-backup.tar.gz
-rw-r--r--. 1 root root 4,9M Feb 17 20:22 etc-backup.tar.gz
We may want to review that same option when decompressing:
[root@rhel-instance ~]# cd tmp/
[root@rhel-instance tmp]# rm -rf etc
[root@rhel-instance tmp]# tar -xzf ../etc-backup.tar.gz
[root@rhel-instance tmp]# ls
etc
As you can see, it’s very easy to pack and compress files using tar and gzip. There are other available compression methods with higher ratios, such as bzip2 or xz, that you may want to try, too. Now, let’s move on to combine all the commands that we have learned into a powerful way to automate – by creating shell scripts.
As a system administrator (or sysadmin), there will be times when you want to run a series of commands more than once. You can do this manually by running each command every time. However, there is a more efficient way to do so – by creating a shell script.
A shell script is nothing more than a text file with a list of commands to be run and a reference to the shell that will interpret it.
In this book, we will not cover how to use a text editor; however, we will provide three recommendations for text editors in Linux that could be of help:
We can create our first shell script by editing a new file called hello.sh with the following line as its content:
echo ''hello world!''
Then, we can run it by using the bash command interpreter with the following line:
[root@rhel-instance ~]# bash hello.sh
hello world!
There is a different way to do this where we do not need to type bash. We can add an initial line referencing the interpreter, so the file content of hello.sh looks as follows:
#!/bin/bash echo ''hello world!''
Now, we change the permissions to make it executable:
[root@rhel-instance ~]# ls -l hello.sh
-rw-r--r--. 1 root root 32 Feb 17 20:32 hello.sh
[root@rhel-instance ~]# chmod +x hello.sh
[root@rhel-instance ~]# ls -l hello.sh
-rwxr-xr-x. 1 root root 32 Feb 17 20:32 hello.sh
And we run it as follows:
[root@rhel-instance ~]# ./hello.sh
hello world!
We have created our first shell script. Congratulations!
Tip
The commands must be in the path to run in any working directory, as stated by the $PATH variable. If our command (or shell script) is not in one of the directories specified in the path, we will specify the running directory, in this case, using the . shortcut for the current directory and the / separator.
Let’s use some variables. We can define a variable by simply providing its name and the value we want. Let’s try replacing world with a variable. To use it, we prepend the $ symbol to the name of the variable and it will be used. The script will look as follows:
#!/bin/bash PLACE=''world'' echo ''hello $PLACE!''
We can run the script, obtaining the same output as before:
[root@rhel-instance ~]# ./hello.sh
hello world!
To have more clarity, when using the value of the variable, we will put the name of it between curly braces, { and }’, and take this as a good practice.
The previous script will look as follows:
#!/bin/bash PLACE=''world'' echo ''hello ${PLACE}!''
We now know how to create a basic script, but we may want to have greater control over it by using some programmatic capabilities, starting with loops. Let’s go for it!
What if we want to run the same command over a list of places? That’s what a for loop is used for. It can help iterate over a set of elements, such as a list or a counter, for example.
The for loop syntax is as follows:
We can define a space-separated list to try it and iterate through it with our first for loop:
#!/bin/bash PLACES_LIST="Madrid Boston Singapore World" for PLACE in ${PLACES_LIST}; do echo "hello ${PLACE}!" done
Let’s run it. The output will look as follows:
[root@rhel-instance ~]# ./hello.sh
hello Madrid!
hello Boston!
hello Singapore!
hello World!
Using the for loop can be very interesting when reading the list from an external command. We can do so by putting the external command between $( and ).
Tip
Backticks, ', can also be used to run a command and get its output as a list, but we will stick to the previous expression for clarity.
One example of a usable external command can be ls. Let’s create the txtfiles.sh script with the following content:
#!/bin/bash for TXTFILE in $(ls *.txt); do echo ''TXT file ${TXTFILE} found! '' done
Make it executable and run it:
[root@rhel-instance ~]# chmod +x txtfiles.sh
[root@rhel-instance ~]# ./txtfiles.sh
TXT file error.txt found!
TXT file non-listing.txt found!
TXT file usr-files.txt found!
TXT file var-files.txt found!
You see how we can now iterate over a set of files, including, for example, changing their names, finding and replacing content in them, or simply making a specific backup of a selection of files.
We’ve seen several ways in which to iterate a list with the for loop, which can be very useful when it comes to automating tasks. Now, let’s move on to another programmatic capability in scripts – conditionals.
Sometimes, we may want to execute something different for one of the elements in a list, or only if a condition is happening. We can use the if conditional for this.
The if conditional syntax is if; to specify the condition.
Conditions are usually specified between brackets ([ and ]):
Let’s change our previous hello.sh script to say "hello to Madrid" in Spanish, as follows:
#!/bin/bash PLACES_LIST="Madrid Boston Singapore World" for PLACE in ${PLACES_LIST}; do if [ ${PLACE} = "Madrid" ]; then echo ''¡Hola ${PLACE}!'' fi done
Then, run it:
[root@rhel-instance ~]# ./hello.sh
¡Hola Madrid!
We have a problem; it only says hello to Madrid. What happens if we want to run the previous code on the ones not matching the condition? That’s when we extend the conditional using else for the items that do not match.
And now, we have an example of a conditional using else:
#!/bin/bash PLACES_LIST="Madrid Boston Singapore World" for PLACE in ${PLACES_LIST}; do if [ ${PLACE} = "Madrid" ]; then echo ''¡Hola ${PLACE}!'' else echo ''hello ${PLACE}!'' fi done
We can run it:
[root@rhel-instance ~]# ./hello.sh
¡Hola Madrid!
hello Boston!
hello Singapore!
hello World!
As you see, it’s simple to use the conditionals in a script and provide a lot of control over the conditions under which a command is run. We now need to control when something may not be running correctly. That’s what the exit codes (or error codes) are for. Let’s go for it!
When a program is run, it provides an exit code, specifying whether it ran OK or whether there was an issue. That exit code is stored in a special variable called $?.
Let’s take a look at it by running ls hello.sh:
[root@rhel-instance ~]# ls hello.sh
hello.sh
[root@rhel-instance ~]# echo $?
0
When the program runs OK, the exit code is zero, 0.
What happens when we try to list a file that doesn’t exist (or run any other command incorrectly, or that is having issues)? Let’s try listing a nonexistent file:
[root@rhel-instance ~]# ls nonexistentfile.txt
ls: cannot access 'nonexistentfile.txt': No such file or directory
[root@rhel-instance ~]# echo $?
2
You see, the exit code is not zero. We will go to the documentation and check the number associated with it to understand the nature of the issue.
When running a command in a script, check for the exit code and act accordingly. Let’s now review where to find further information on the commands, such as exit codes or other options, in the following section.
The system includes resources to help you while working with it and guide you to improve your sysadmin skills. This is referred to as the system documentation. Let’s check three different resources available by default in your RHEL installation: man pages, info pages, and other documents.
The most common resource used to obtain documentation is manual pages, also referred to by the command used to invocate them: man.
Almost any utility installed in the system has a man page to help you use it (in other words, specifying all the options for the tools and what they do). You can run man tar and check the output:
[root@rhel-instance ~]# man tar
TAR(1) GNU TAR Manual TAR(1)
NAME
tar - an archiving utility
SYNOPSIS
Traditional usage
tar {A|c|d|r|t|u|x}[GnSkUWOmpsMBiajJzZhPlRvwo] [ARG...]
UNIX-style usage
tar -A [OPTIONS] ARCHIVE ARCHIVE
tar -c [-f ARCHIVE] [OPTIONS] [FILE...]
tar -d [-f ARCHIVE] [OPTIONS] [FILE...]
You can see in it (navigate with the arrow keys, the space bar, or Page Up and Page Down) and exit it by hitting q (for quit).
There are sections within the man page on related topics. It is pretty simple to search those by using the apropos command. Let’s see this for tar:
[root@rhel-instance ~]# apropos tar
dbus-run-session (1) - start a process as a new D-Bus session
dnf-needs-restarting (8) - DNF needs_restarting Plugin
dracut-pre-udev.service (8) - runs the dracut hooks before udevd is started
gpgtar (1) - Encrypt or sign files into an archive
gtar (1) - an archiving utility
open (1) - start a program on a new virtual terminal (VT).
openvt (1) - start a program on a new virtual terminal (VT).
scsi_start (8) - start one or more SCSI disks
setarch (8) - change reported architecture in new program environment and set personalit...
sg_reset (8) - sends SCSI device, target, bus or host reset; or checks reset state
sg_rtpg (8) - send SCSI REPORT TARGET PORT GROUPS command
sg_start (8) - send SCSI START STOP UNIT command: start, stop, load or eject medium
sg_stpg (8) - send SCSI SET TARGET PORT GROUPS command
systemd-notify (1) - Notify service manager about start-up completion and other daemon status c...
systemd-rc-local-generator (8) - Compatibility generator for starting /etc/rc.local and /usr/sbin...
systemd.target (5) - Target unit configuration
tar (1) - an archiving utility
tar (5) - format of tape archive files
unicode_start (1) - put keyboard and console in unicode mode
As you can see, it matches not only tar but also start. This isn’t perfect, but it can provide helpful information related to tar, such as gpgtar.
man pages have sections. As you can see in the previous example, for tar, there are manual pages in two sections, one for the command-line utility (section 1), and one for the archiving format (section 5):
tar (1) - an archiving utility
tar (5) - format of tape archive files
We can access the page in section 5 to understand the format by running the following command:
[root@rhel-instance ~]# man 5 tar
Now, we can see the tar format page:
TAR(5) BSD File Formats Manual TAR(5)
NAME
tar — format of tape archive files
DESCRIPTION
The tar archive format collects any number of files, directories, and other file system objects (symbolic links, device nodes, etc.) into a single stream of bytes. The format was ...
You can see that manual pages are a great resource for learning more about the typical commands being used. This is also a fantastic resource as far as the Red Hat Certified System Administrator exam is concerned. One recommendation is to review all man pages for the commands shown previously in this chapter, as well as for the forthcoming chapters. Consider man pages the main information resource in the system. Let’s now review other information resources available.
info pages are usually more descriptive than man pages and are more interactive. They help more in getting started on a topic.
We can try to get info for the ls command by running the following:
[root@rhel-instance ~]# info ls
Important Note
If the info command is not available, you can install it first using the dnf install info –y command.
We can see the info page for it:
Next: dir invocation, Up: Directory listing
10.1 'ls': List directory contents
==================================
The 'ls' program lists information about files (of any type, including
directories). Options and file arguments can be intermixed arbitrarily,
info pages can redirect to other topics, shown underlined, and these can be followed by putting the cursor over them and hitting Enter.
As with man pages, press q to quit.
Please take some time to review the info pages for the main topics covered in this chapter (in several cases, info pages will not be available, but the ones that are will be very valuable).
What if we do not find a man or info page for a topic? Let’s cover this in the following section.
For other documentation resources, you can go to the /usr/share/doc directory. There, you will find other documents that come with the tools installed in the system.
Let’s see how many items we have:
[root@rhel-instance doc]# cd /usr/share/doc/
[root@rhel-instance doc]# ls | wc -l
333
You can see that there are 333 directories available under /usr/share/doc.
As a good example, let’s enter the bash directory:
[root@rhel-instance doc]# cd bash/
Then, let’s take a look at the INTRO file using less to read it (remember, you use q to quit):
[root@rhel-instance bash]# ls
bash.html bashref.html FAQ INTRO RBASH README
[root@rhel-instance bash]# less INTRO
BASH - The Bourne-Again Shell
Bash is the shell, or command language interpreter, that will appear in the GNU operating system. Bash is an sh-compatible shell that
incorporates useful features from the Korn shell (ksh) and C shell
(csh). It is intended to conform to the IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools standard. It offers functional improvements
This is a good read for a better understanding of bash. Now, you have a lot of documentation resources that you will be able to use during your daily tasks, as well as in the RHCSA exam.
In this chapter, we have learned about how to log in to a system with user and with root, understanding the basics of permissions and security. We are now also more comfortable using the command line with auto-complete, navigating through the directories and files, packing and unpacking them, redirecting command output and parsing it, and even automating processes with shell scripts. More importantly, we have a way to obtain information on what we are doing (or want to do) available in any RHEL system with the included documentation. These skills are the basis of the upcoming chapters. Don’t hesitate to revisit this chapter if you feel stuck or if your progress is not as fast as you thought.
Now, it is time to extend your knowledge to encompass more advanced topics in the upcoming chapters. In the following chapter, you will be getting used to the tools for regular operations, in which you will review the most common actions taken when managing a system. Enjoy!
18.118.252.87