Executing Multiple Commands at Once
From either the command-line or from within shell scripts, it’s handy to know how to combine multiple commands into one single command. In this section, I’ll demonstrate three ways to do that which are:
- Running commands interactively
- Using command sequences
- Using the
find
utility
Running Commands Interactively
This is a form of shell-script programming, except that you’re just executing all commands from the command-line, instead of actually writing, saving, and executing a script. Here, you are creating a for loop – with each command of the loop on its own separate line – to perform a directory listing three times.
[donnie@fedora ~]$ for var in arg1 arg2 arg3
> do
> echo $var
> ls
> done
. . .
. . .
[donnie@fedora ~]$
At the end of each line, you’ll hit the Enter key. But, nothing will happen until you type the done
command on the final line. The for
loop will then run three times, once for each of the three listed arguments. Each time that it runs, the value of an argument gets assigned to the var
variable, and the echo
command prints the currently-assigned value. The output will look something like this:
arg1
4-2_Building_an_Alpine_Container.bak Public
4-2_Building_an_Alpine_Container.pptx pwsafe.key
arg2
4-2_Building_an_Alpine_Container.bak Public
4-2_Building_an_Alpine_Container.pptx pwsafe.key
arg3
4-2_Building_an_Alpine_Container.bak Public
4-2_Building_an_Alpine_Container.pptx pwsafe.key
Next, hit the up arrow key on your keyboard, and you’ll see the for
loop that you just executed If you try this with bash
, you’ll see that the individual commands are separated by semi-colons, like so:
[donnie@fedora ~]$ for var in arg1 arg2 arg3; do echo $var; ls; done
On zsh
, pressing the up arrow key will cause the command components to appear on their own separate lines, as you see here:
donnie@opensuse:~> for var in arg1 arg2 arg3
do
echo $var
ls
done
Either way, the for
loop will run again when you hit the Enter key.
If you’re still a bit unclear about how for
loops work, have no fear. We’ll look at them in greater detail once we start actually creating shell scripts.
Using Command Sequences
Command sequences are another type of programming structure that you’ll find very useful. Here, I’m demonstrating how to use them from the command-line so that you can grasp the basic concepts. In the upcoming chapters, I’ll show you examples of how to use them in shell scripts.
Chaining Commands with a Semi-Colon
You can also use the semi-colon to separate stand-alone commands that you want to execute from the same command entry. If you wanted to cd
to a certain directory and then look at its contents, you could enter each command on its own line. Or, you could enter them both on the same line. This process is called command chaining, which looks like this:
[donnie@fedora ~]$ cd /var ; ls
account cache db ftp kerberos local log nis preserve spool yp
adm crash empty games lib lock mail opt run tmp
[donnie@fedora var]$
[donnie@fedora ~]$ cd /far ; ls
bash: cd: /far: No such file or directory
4-2_Building_an_Alpine_Container.bak Public
4-2_Building_an_Alpine_Container.pptx pwsafe.key
addresses.txt python_container
alma9_default.txt rad-bfgminer
. . .
. . .
[donnie@fedora ~]$
The first command failed because I tried to cd
into a non-existent directory. But, the second command still executed, which listed the files in my home directory.
Conditional Command Execution with Double Ampersands
You can also instruct bash
or zsh
to only execute the second command if the first command successfully completes. Just separate the commands with &&
instead of with a semi-colon, like this:
[donnie@fedora ~]$ cd /var && ls
account cache db ftp kerberos local log nis preserve spool yp
adm crash empty games lib lock mail opt run tmp
[donnie@fedora var]$
What if the first command doesn’t run successfully? Note here that the second command doesn’t execute:
[donnie@fedora ~]$ cd /far && ls
bash: cd: /far: No such file or directory
[donnie@fedora ~]$
Conditional Command Execution with Double Pipes
If you want bash
or zsh
to execute the second command only if the first command doesn’t run successfully, just separate the commands with ||
. (This is a pair of pipe characters, which you’ll find on the same key as the backslash.) To illustrate, let’s again make a slight typo while trying to change directories.
[donnie@fedora ~]$ ce /var || echo "This command didn't work."
bash: ce: command not found
This command didn't work.
[donnie@fedora ~]$
[donnie@fedora ~]$ cd /var || echo "This command didn't work."
[donnie@fedora var]$
For a more practical example, try changing to a directory, creating it if it doesn’t exist, and then changing to it after it’s been successfully created.
[donnie@fedora ~]$ cd mydirectory || mkdir mydirectory && cd mydirectory
bash: cd: mydirectory: No such file or directory
[donnie@fedora mydirectory]$
You’ll still get an error message saying that the directory you tried to access doesn’t exist. But, look at the command prompt, and you’ll see that the directory has been created, and that you’re now in it.
Using the find Utility
We’ll now take a short intermission from our discussion of running multiple commands in order to introduce the find
utility, which is truly the Cool-Mac Daddy of all search utilities. After this introduction, I’ll use find
to show you more ways to run multiple commands at once.
Also, it would behoove us to mention that find
isn’t just good for command-line searches. It’s also excellent for use within shell scripts, as you’ll see much later.
If you’re as old as I am, you might remember the Windows XP search pooch, which pranced around on your screen every time you did a file search from the Windows XP graphical search utility. It was cute, but it didn’t add to your search power. With the Linux find
utility, you can perform powerful searches on just about any criterion you can think of, and then--from the same command-line entry--invoke another utility to do whatever you need to do with the search results. I won’t try to discuss every option there is for find
, since there are so many. Rather, I’ll give you an overview of what you can do with find
, and let you read its man page for the rest. (Just enter man find
at the command-line to read about all of its options.)
In order to perform the most basic of searches, you’ll need to specify two things:
- The search path: You can perform a search in either a specific path, or the entire filesystem. Since
find
is inherently recursive, the search will automatically extend to all of the subdirectories that are beneath of the directory that you specify. (Of course, you can also add command switches that limit the depth of the search.) - What you’re searching for: There are a lot of ways that you can specify this. You can search for files of a specific name, and decide whether to make the search case-sensitive. You can also use wildcards, or search for files with certain characteristics or that are of a certain age. Or, you can combine multiple criteria for even more specific searches. The main thing that limits you is your own imagination.
So now, let’s say that you want to search the entire filesystem for all files whose names end in .conf
. You’ll want to use either the -name
or the -iname
switch in front of the file description that you want to search for. Otherwise, you’ll get a jumbled up mess of every directory listing that you’ve searched, with the information you’re looking for mixed in. For case-sensitive searches, use -name
, and for case-insensitive searches, use -iname
. In this case, we’ll use -iname
, since we want to make the search case-insensitive.
I know, I’ve told you previously that most whole-word option switches are preceded by a pair of dashes. The find
utility is an exception to the rule, because its whole-word option switches are preceded by only a single dash.
Also, be aware that searching through an entire filesystem on a production server with very large drives can take a long time. It’s sometimes necessary to do that, but it’s best to confine your searches to specific directories whenever possible.
If you include a wildcard character with a search criterion, you’ll need to enclose that search criterion in quotes. That will keep the shell from interpreting the wildcard character as an ambiguous file reference. For example, to perform a case-insensitive search through the current working directory and all of its subdirectories for all files with names ending with a .conf
filename extension, I would do this:
[donnie@fedora ~]$ find -iname '*.conf'
./.cache/containers/short-name-aliases.conf
./.config/lxsession/LXDE/desktop.conf
./.config/pcmanfm/LXDE/desktop-items-0.conf
./.config/pcmanfm/LXDE/pcmanfm.conf
./.config/lxterminal/lxterminal.conf
./.config/Trolltech.conf
. . .
. . .
./tor-browser/Browser/TorBrowser/Data/fontconfig/fonts.conf
./rad-bfgminer/example.conf
./rad-bfgminer/knc-asic/RPi_system/raspi-blacklist.conf
./something.CONF
[donnie@fedora ~]$[donnie@fedora ~]$
By using the -iname
option, I was able to find files with names that ended in either .conf
or .CONF
. If I had used the -name
option instead, I would only have found files with names that end in .conf
.
Normally, you would specify the search path as the first component of the find
command. In the GNU implementation of find
that’s included on Linux-based operating systems, omitting the search path will cause find
to search through the current working directory, as we’ve just seen. Unfortunately, that trick doesn’t work for Unix/Unix-like operating systems, such as FreeBSD, macOS, or OpenIndiana. For those operating systems, you’ll always need to specify a search path. To make find
search through the current working directory, just use a dot to specify the search path. So, on my FreeBSD virtual machine, the command looks like this:
donnie@freebsd-1:~ $ find . -iname '*.conf'
./anotherdir/yetanother.conf
./anotherthing.CONF
./something.conf
donnie@freebsd-1:~ $
Okay, I know. You’re wondering why I’m mentioning FreeBSD, macOS, and OpenIndiana in what’s supposed to be a Linux book. Well, it’s because sometimes, we’ll want to create shell scripts that work on multiple operating systems, rather than just on Linux. If you include the dot in this command, it will still work on your Linux machines, and will also work on your Unix/Unix-like machines.
You can also specify search paths that aren’t your current working directory. For example, you can remain within your own home directory and search through the entire filesystem like this:
[donnie@fedora ~]$ find / -iname '*.conf'
Of course, this will take much longer than it does to just search through one directory. Also, you’ll encounter errors because your normal user account won’t have permission to go into every directory. To search through all directories on the filesystem, just preface the command with sudo
, like this:
[donnie@fedora ~]$ sudo find / -iname '*.conf'
You can perform searches with more than one search criterion. If you separate the criteria with a space, it will be the same as placing an and
operator between them. Here, we’ll use the -mtime -7
switch to find all of the .conf
files that were modified within the last seven days, and the -ls
switch at the end to show detailed information about the files:
[donnie@fedora ~]$ sudo find / -iname '*.conf' -mtime -7 -ls
18 4 -rw-r--r-- 1 root root 328 Jul 24 17:50 /boot/loader/entries/81085aed13d34626859063e7ebf29da5-6.4.4-100.fc37.x86_64.conf
3321176 4 -rw-r--r-- 1 donnie donnie 467 Jul 24 16:14 /home/donnie/.config/pcmanfm/LXDE/pcmanfm.conf
370 4 -rw-r--r-- 1 donnie donnie 3272 Jul 19 16:21 /home/donnie/.config/Trolltech.conf
. . .
. . .
4120762 8 -rw-r--r-- 2 root root 7017 Jul 21 14:43 /var/lib/flatpak/app/com.notepadqq.Notepadqq/x86_64/stable/a049a1963430515aa15d950212fc1f0db7efb703a94ddd1f1d316b38ad12ec72/files/lib/node_modules/npm/node_modules/request/node_modules/http-signature/node_modules/jsprim/node_modules/verror/jsl.node.conf
[donnie@fedora ~]$
To search for .conf
files that were modified more than seven days ago, replace the -7
with +7
, like this:
[donnie@fedora ~]$ sudo find / -iname '*.conf' -mtime +7 -ls
It’s also possible to create more advanced searches by creating compound expressions. It works like Algebra, in that expressions are evaluated from left to right unless you group some of the terms with parentheses. But, with that, there are a couple of minor catches.
Since the parenthesis symbols have a special meaning in bash
and zsh
, you’ll want to precede them with a backslash so that bash
and zsh
won’t interpret them the wrong way. You’ll also need to leave a space between the parenthesis symbols and the terms that they’re enclosing.
Let’s say that we now want to look for all of the .conf
files in the /etc/
directory that were either modified within the last seven days, or that were accessed more than 30 days ago. We’ll use the -atime
switch to set the access time criterion. The or
operator is represented by -o
.
[donnie@fedora ~]$ sudo find /etc -iname '*.conf' \( -mtime -7 -o -atime +30 \)
[sudo] password for donnie:
/etc/UPower/UPower.conf
/etc/X11/xinit/xinput.d/ibus.conf
/etc/X11/xinit/xinput.d/xcompose.conf
/etc/X11/xinit/xinput.d/xim.conf
. . .
. . .
/etc/appstream.conf
/etc/whois.conf
/etc/nfsmount.conf
[donnie@fedora ~]$
There are several subdirectories in /etc/
that require root privileges to enter, so I used sudo
again, as I did before. Adding the -ls
option at the end of the command would show the timestamps on the files, which would tell me which of the two search criteria applies to each specific file.
If you want to find files that belong to only a certain user, you can do that with the -user
switch. Add a second criterion to find only files of a certain type that belong to a certain user. Here, I’m searching through the whole filesystem for all .png
graphics files that belong to me:
[donnie@fedora ~]$ sudo find / -user donnie -iname '*.png'
/home/donnie/.cache/mozilla/firefox/xgwvyw2p.default-release/thumbnails/9aa3453b0b6246665eb573e58a40fe7c.png
/home/donnie/.cache/mozilla/firefox/xgwvyw2p.default-release/thumbnails/96c0e5aa4c2e735c2ead0701d2348dd6.png
. . .
. . .
/home/donnie/rad-bfgminer/vastairent.png
find: '/run/user/1000/doc': Permission denied
find: '/run/user/1000/gvfs': Permission denied
/tmp/.org.chromium.Chromium.IpK3VA/pcloud1_16.png
find: '/tmp/.mount_pcloudWz4ji1': Permission denied
[donnie@fedora ~]$
Even with full sudo
privileges, there are still a couple of directories where I’m not allowed to access. But, that’s okay.
You can use the -group
switch to find files that belong to a certain group. Here, I’m looking through my own home directory for either files or directories that are associated with the nobody
group.
[donnie@fedora ~]$ sudo find -group nobody -ls
3344421 0 drwxr-xr-x 1 nobody nobody 0 Jul 25 18:36 ./share
3344505 0 -rw-r--r-- 1 donnie nobody 0 Jul 25 18:38 ./somefile.txt
[donnie@fedora ~]$
Note that I’m still using sudo
here, because even in my own home directory there are some directories that find
won’t access without it. (These are the directories that contain information about Docker containers.)
Conversely, you can use the -nogroup
switch to find files that don’t belong to any group that’s listed in the /etc/group
file.
[donnie@fedora ~]$ sudo find -nogroup
./.local/share/containers/storage/overlay/994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7/diff/etc/shadow
./.local/share/containers/storage/overlay/ded7a220bb058e28ee3254fbba04ca90b679070424424761a53a043b93b612bf/diff/etc/shadow
./.local/share/containers/storage/overlay/8e012198eea15b2554b07014081c85fec4967a1b9cc4b65bd9a4bce3ae1c0c88/diff/etc/shadow
./.local/share/containers/storage/overlay/7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39/diff/etc/shadow
[donnie@fedora ~]$
In the Linux/Unix world, everything on the system is represented by a file. Normal users of a system will usually just encounter regular files and directories, but there are many other types of files that will be of interest to a system administrator. The various file types include:
- Regular files: These are the types of files that a normal user would routinely access. Graphics files, video files, database files, spreadsheet files, text files, and executable files are all examples of regular files.
- Directories: It seems strange that a directory is a type of file, but that’s just how it is in the Linux and Unix worlds.
- Character devices: A character device either accepts or supplies a serial stream of data. A sound card or a terminal would be represented by a character device file. You’ll find these files in the
/dev/
directory. - Block devices: A block device file represents devices that can be accessed in a random manner. Examples include hard drives, solid-state drives, and drive partitions. You’ll also find these files in the
/dev/
directory. - Named pipes: These devices take the output from one system process and supply it as the input to another system process, thus enabling inter-process communication.
- Sockets: These are the same as named pipes, except that they can send and receive file descriptors as part of the communications stream. Also, unlike named pipes, sockets can allow two-way data exchange between two processes.
- Symbolic links: This type of file simply points to either a regular file or directory. This allows users to either access files and directories from multiple places in the filesystem, or to access them by different names.
You can tell what type a file is by doing an ls -l
command. The first character in the output for each file is known as the file mode string. This file mode string designates the file type. For example, let’s look at what’s in my home directory:
[donnie@fedora ~]$ ls -l
total 137972
-rw-r--r--. 1 donnie donnie 12111206 Feb 18 13:41 dnf_list.txt
drwxr-xr-x. 15 donnie donnie 4096 Jul 27 16:39 orphaned_files
drwxr-xr-x. 2 donnie donnie 6 Jul 29 16:53 perm_demo
-rw-r--r--. 1 donnie donnie 643 Mar 26 15:53 sample.json
[donnie@fedora ~]$
Lines that begin with a -
represent a regular file, and lines that begin with a d
represent a directory. The various file types are represented as follows:
File mode string |
File type |
|
Regular file |
|
Directory |
|
Character device |
|
Block device |
|
Named pipe |
|
Socket |
|
Symbolic link |
Table 2.1: File type designators
There may be times when you’ll need to locate all files of a certain type. You can do that with the -type
option, like so:
[donnie@fedora ~]$ sudo find / -type p -ls
545 0 prw------- 1 root root 0 Jul 31 15:20 /run/initctl
542 0 prw------- 1 root root 0 Jul 31 15:20 /run/dmeventd-client
541 0 prw------- 1 root root 0 Jul 31 15:20 /run/dmeventd-server
6 0 p--------- 1 donnie donnie 0 Jul 31 15:29 /run/user/1000/systemd/inaccessible/fifo
1228 0 prw------- 1 root root 0 Jul 31 15:21 /run/systemd/inhibit/2.ref
1193 0 prw------- 1 root root 0 Jul 31 15:21 /run/systemd/inhibit/1.ref
1324 0 prw------- 1 root root 0 Jul 31 15:29 /run/systemd/sessions/3.ref
1311 0 prw------- 1 root root 0 Jul 31 15:29 /run/systemd/sessions/1.ref
8 0 p--------- 1 root root 0 Jul 31 15:20 /run/systemd/inaccessible/fifo
112 0 prw------- 1 root root 0 Jul 31 15:20 /var/lib/nfs/rpc_pipefs/gssd/clntXX/gssd
[donnie@fedora ~]$
As you see, I’m using the -type p
option to search for all named pipe files.
Now, let’s consider the previous example in which we searched for all files that end with a .conf
filename extension:
[donnie@fedora ~]$ sudo find / -iname '*.conf'
This command only found regular files because they’re the only types of files on the system that have the .conf
filename extension. But, let’s now say that we want to search through the /etc/
directory to find all subdirectories with the conf
text string in their names. If we don’t specify a file type, we’ll see regular files, symbolic links, and directories:
[donnie@fedora ~]$ sudo find /etc -name '*conf*' -ls
329486 4 -rw-r--r-- 1 root root 351 Jul 27 07:02 /etc/dnf/plugins/copr.conf
329487 4 -rw-r--r-- 1 root root 30 Jul 27 07:02 /etc/dnf/plugins/debuginfo-install.conf
8480155 4 -rw-r--r-- 1 root root 93 May 18 04:27 /etc/dnf/protected.d/dnf.conf
. . .
25325169 0 lrwxrwxrwx 1 root root 43 Jul 29 18:19 /etc/crypto-policies/back-ends/bind.config -> /usr/share/crypto-policies/DEFAULT/bind.txt
25325172 0 lrwxrwxrwx 1 root root 45 Jul 29 18:19 /etc/crypto-policies/back-ends/gnutls.config -> /usr/share/crypto-policies/DEFAULT/gnutls.txt
. . .
5430579 0 drwxr-xr-x 2 root root 25 Sep 19 2022 /etc/reader.conf.d
8878157 0 drwxr-xr-x 3 root root 27 Dec 8 2022 /etc/pkgconfig
8927250 0 drwxr-xr-x 2 root root 83 Nov 16 2022 /etc/krb5.conf.d
. . .
[donnie@fedora ~]$
We’ll use the -type d
option to narrow things down:
[donnie@fedora ~]$ sudo find /etc -name '*conf*' -type d -ls
17060336 0 drwxr-xr-x 2 root root 41 Dec 8 2022 /etc/fonts/conf.d
25430579 0 drwxr-xr-x 2 root root 25 Sep 19 2022 /etc/reader.conf.d
8878157 0 drwxr-xr-x 3 root root 27 Dec 8 2022 /etc/pkgconfig
8927250 0 drwxr-xr-x 2 root root 83 Nov 16 2022 /etc/krb5.conf.d
25313333 0 drwxr-xr-x 2 root root 6 Feb 1 17:58 /etc/security/pwquality.conf.d
25395980 0 drwxr-xr-x 2 root root 30 Dec 8 2022 /etc/X11/xorg.conf.d
17060487 0 drwxr-xr-x 2 root root 6 Aug 9 2022 /etc/pm/config.d
. . .
. . .
16917753 0 drwxr-xr-x 2 root root 33 Jul 29 18:11 /etc/containers/registries.conf.d
[donnie@fedora ~]$
Cool. We now only see the directories, which is exactly what we want.
As I said before, there are a lot of options that you can use with the find
utility. (Enter man find
to see them all.)
Now, with the introduction to find
out of the way, let’s look at how to use find
to perform multiple actions with one command.
Performing Multiple Actions with find
Our next trick contains a bit of a twist. We’ll use find
's -exec
and -ok
option switches to make find
perform some sort of action on each file that it finds. First, find
finds the files. Then, it causes another command to run that will take some sort of action on the files. Here’s how it works.
The -exec
and -ok
switches tell the shell to perform a second command only if the first command produces valid output. It then uses the output of the first command (find
) as arguments for the second. The difference between the two switches is that -exec
causes the desired action to automatically execute on each file without prompting the user. The -ok
switch will cause the action to stop after each file that find
finds, asking the user whether or not to proceed with the action for that file. Here, we’re searching the entire filesystem for all .zip
files that are more than 30 days old, and copying them to the /home/donnie/
directory. (Note that I’m still using sudo
so that I can access all directories.)
[donnie@fedora ~]$ sudo find / \( -mtime +30 -iname '*.zip' \) -exec cp {} /home/donnie \;
The {}
after the cp
command tells bash
or zsh
, “Take the results from the find
command, and put them here as the arguments”. Note that this command sequence has to end with a semi-colon. But, since the semi-colon has special meaning for bash
and zsh
, you must precede it with a backslash so that bash
and zsh
will interpret it correctly.
Also, note that you must have a blank space after the first parenthesis, and another blank space before the backslash that precedes the last parenthesis.
Now, suppose that you only want to copy over some of the files that you find. Just replace the -exec
switch with the -ok
switch. It works the same as -exec
, but it will ask permission before performing an operation on a file. You’ll have to enter either y or n before continuing to the next file.
The same principle also works for removing files.
[donnie@fedora ~]$ sudo find / \( -mtime +30 -iname '*.zip' \) -ok rm {} \;
Let’s now suppose that Vicky, Cleopatra, Frank, and Goldie are all creating graphics for some sort of project. They’re supposed to place the graphics files into the graphics
subdirectory that each of them have in their own home directory. Sometimes they forget though, and place the files into their top-level home directories, as we see in the following diagram:
Figure 2.1: Some of these graphics files are in the wrong place.
Now, let’s get a bit of hands-on practice with this.
Hands-on Lab – Using find to Perform Other Commands
For this lab, use a Fedora, Debian, or Ubuntu virtual machine. (I’ll provide instructions for all of them.)
Let’s say that we want to copy everyone’s graphics files into a common backup directory.
- First, create the
/backup
directory, like this:[donnie@fedora ~]$ sudo mkdir /backup
For our present purposes, just leave ownership and permissions settings as they are.
- Next, create user accounts for Vicky, Cleopatra, Frank, and Goldie, and assign a password to each account. On Fedora, the commands would look like this:
donnie@fedora:~$ sudo useradd frank donnie@fedora:~$ sudo passwd frank
On either Debian or Ubuntu, use the interactive adduser
command, which both creates the user account and sets the password. It looks like this:
donnie@debian12:~$ sudo adduser goldie
- Log into each user’s account, create a
graphics
directory in each user’s home directory, and then create some fake graphics files. Here are the commands to do that:goldie@fedora:~$ touch goldie02.png goldie@fedora:~$ mkdir graphics goldie@fedora:~$ cd graphics/ goldie@fedora:~/graphics$ touch {goldie01.png,goldie03.png,goldie04.png} goldie@fedora:~/graphics$
The touch
command is actually meant to be used by programmers for purposes that I won’t go into here. But, it’s also handy for situations like this, when you just need to create some fake files for testing purposes. By enclosing a comma-separated list of filenames within a pair of curly braces, you can create multiple files with just one single command. To verify that, let’s peek into the graphics
directory:
goldie@fedora:~/graphics$ ls -l
total 0
-rw-r--r--. 1 goldie goldie 0 Mar 23 13:27 goldie01.png
-rw-r--r--. 1 goldie goldie 0 Mar 23 13:27 goldie03.png
-rw-r--r--. 1 goldie goldie 0 Mar 23 13:27 goldie04.png
goldie@fedora:~/graphics$
- For this step, you’ll need to log back into your own user account. You want to be sure to get all of the graphics files, even if they’re in the users’ top-level home directories, and copy them into the
/backup/
directory. Your command and results would look like this:[donnie@fedora ~]$ sudo find /home -name '*.png' -exec cp {} /backup \; [donnie@fedora ~]$ ls -l /backup/ total 0 -rw-r--r--. 1 root root 0 Jul 28 15:40 cleopatra01.png -rw-r--r--. 1 root root 0 Jul 28 15:40 cleopatra02.png -rw-r--r--. 1 root root 0 Jul 28 15:40 cleopatra03.png -rw-r--r--. 1 root root 0 Jul 28 15:40 cleopatra04.png -rw-r--r--. 1 root root 0 Jul 28 15:40 frank01.png -rw-r--r--. 1 root root 0 Jul 28 15:40 frank02.png -rw-r--r--. 1 root root 0 Jul 28 15:40 frank03.png -rw-r--r--. 1 root root 0 Jul 28 15:40 frank04.png -rw-r--r--. 1 root root 0 Jul 28 15:40 goldie01.png -rw-r--r--. 1 root root 0 Jul 28 15:40 goldie02.png -rw-r--r--. 1 root root 0 Jul 28 15:40 goldie03.png -rw-r--r--. 1 root root 0 Jul 28 15:40 goldie04.png -rw-r--r--. 1 root root 0 Jul 28 15:40 vicky01.png -rw-r--r--. 1 root root 0 Jul 28 15:40 vicky02.png -rw-r--r--. 1 root root 0 Jul 28 15:40 vicky03.png -rw-r--r--. 1 root root 0 Jul 28 15:40 vicky04.png [donnie@fedora ~]$
What I’ve shown you here just barely scratches the surface of what you can do with find
. To see the complete list of search criteria that you can specify, open the find
man page and scroll down to the TESTS section.
We’ll look at some more find
examples a bit later. For now though, let’s look at how to create recursive commands.