Classic Shell Scripting - Arnold Robbins [153]
Automated execution of commands on selected files is both powerful and extremely dangerous. If that command is destructive, it may be better to let find produce the list in a temporary file first, and then have a competent human carefully examine that list before deciding whether to hand it off to some command for further automated processing.
Shell scripts that use find for destructive purposes must be written carefully, and then debugged with dry runs that, for example, insert the echo command at the start of the destructive command so that you can see what would have been done without actually doing it.
We are now ready for the simplest example: a bare find finds everything in the current directory tree. As before, we start with an empty directory, then populate it with a few empty files:
$ ls
Verify that we have an empty directory
$ mkdir -p sub/sub1
Create a directory tree
$ touch one two .uno .dos
Create some empty top-level files
$ touch sub/three sub/sub1/four
Create some empty files deeper in the tree
$ find
Find everything from here down
.
./sub
./sub/sub1
./sub/sub1/four
./sub/three
./one
./two
./.uno
./.dos
That jumbled list is easily sorted:
$ find | LC_ALL=C sort
Sort find's output into traditional order
.
./.dos
./.uno
./one
./sub
./sub/sub1
./sub/sub1/four
./sub/three
./two
We set LC_ALL to get the traditional (ASCII) sort order, since modern sort implementations are locale-aware, as we described in Section 4.1.1.
find has a useful option, -ls, that gives output vaguely similar to what ls -liRs would give. However, it lacks further options to control the format of this verbose display:
$ find -ls
Find files, and use ls-style output
1451550 4 drwxr-xr-- 3 jones devel 4096 Sep 26 09:40 .
1663219 4 drwxrwxr-x 3 jones devel 4096 Sep 26 09:40 ./sub
1663220 4 drwxrwxr-x 2 jones devel 4096 Sep 26 09:40 ./sub/sub1
1663222 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./sub/sub1/four
1663221 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./sub/three
1451546 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./one
1451547 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./two
1451548 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./.uno
1451549 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./.dos
$ find -ls | sort -k11
Find files, and sort by filename
1451550 4 drwxr-xr-- 3 jones devel 4096 Sep 26 09:40 .
1451549 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./.dos
1451548 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./.uno
1451546 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./one
1663219 4 drwxrwxr-x 3 jones devel 4096 Sep 26 09:40 ./sub
1663220 4 drwxrwxr-x 2 jones devel 4096 Sep 26 09:40 ./sub/sub1
1663222 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./sub/sub1/four
1663221 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./sub/three
1451547 0 -rw-rw-r-- 1 jones devel 0 Sep 26 09:40 ./two
For comparison, here is how ls displays the same file metadata:
$ ls -liRs *
Show ls recursive verbose output
752964 0 -rw-rw-r-- 1 jones devel 0 2003-09-26 09:40 one
752965 0 -rw-rw-r-- 1 jones devel 0 2003-09-26 09:40 two
sub:
total 4
752963 4 drwxrwxr-x 2 jones devel 4096 2003-09-26 09:40 sub1
752968 0 -rw-rw-r-- 1 jones devel 0 2003-09-26 09:40 three
sub/sub1:
total 0
752969 0 -rw-rw-r-- 1 jones devel 0 2003-09-26 09:40 four
Now let's give the find command some file patterns:
$ find 'o*'
Find files in this directory starting with "o"
one
$ find sub
Find files in directory sub
sub
sub/sub1
sub/sub1/four
sub/three