With GNU or FreeBSD find
, you can use the -quit
predicate:
find . ... -print -quit
The NetBSD find
equivalent:
find . ... -print -exit
If all you do is printing the name, and assuming the filenames don't contain newline characters, you could do:
find . ... -print | head -n 1
That will not stop find
after the first match, but possibly, depending on timing and buffering upon the second match or (much) later. Basically, find
will be terminated with a SIGPIPE when it tries to output something while head
is already gone because it has already read and displayed the first line of input.
Note that not all shells will wait for that find
command after head
has returned. The Bourne shell and AT&T implementations of ksh
(when non-interactive) and yash
(only if that pipeline is the last command in a script) would not, leaving it running in background. If you'd rather see that behaviour in any shell, you could always change the above to:
(find . ... -print &) | head -n 1
If you're doing more than printing the paths of the found files, you could try this approach:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(replace printf
with whatever you would be doing with that file).
That has the side effect of find
returning an exit status reflecting the fact that it was killed though.
Actually, using the SIGPIPE signal instead of SIGTERM (kill -s PIPE
instead of kill
) will cause some shells to be more silent about that death (but would still return a non-zero exit status).
With GNU mv:
find path_A -name '*AAA*' -exec mv -t path_B {} +
That will use find's -exec
option which replaces the {}
with each find result in turn and runs the command you give it. As explained in man find
:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command until
an argument consisting of `;' is encountered.
In this case, we are using the +
version of -exec
so that we run as few mv
operations as possible:
-exec command {} +
This variant of the -exec action runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invoca‐
tions of the command will be much less than the number of
matched files. The command line is built in much the same way
that xargs builds its command lines. Only one instance of `{}'
is allowed within the command. The command is executed in the
starting directory.
Best Answer
Adding a slash at the end of the destination path
/opt/alfresco/archived/2020-01-07
would have made themv
command error out, as the2020-01-07
directory evidently does not exist. This would have saved your files.They would also have been saved if
/opt/alfresco/archived/2020-01-07
had been an existing directory (regardless of whether the destination path had a slash at the end or not), and your files would have been moved into that directory (filename collisions may still have been an issue though, as you move files from several directories into a single directory). This is what you wanted to do. What you forgot to do was to create that directory first.Now, since the directory did not exist, what the
find
command did was to take each individual XML and PDF file, rename it to/opt/alfresco/archived/2020-01-07
, and then continue doing the same with the next file, overwriting the previous.The file
/opt/alfresco/archived/2020-01-07
is now the last XML or PDF file found byfind
.Also note that since you ran your
find
command across/opt/alfresco
, any PDF or XML file below that path, for example in any directory beneath/opt/alfresco/archived
, would have met the same fate.This is such an easy error to make. There is no convenient way to recover the lost files other than restoring them from your backups.
If you do not take hourly backups of your data, this may be a good point in time to start looking into doing that. I would recommend
restic
orborgbackup
for doing backups of personal files, preferably against some sort of off-site or at least external storage.The following questions and answers may be of some help:
In your next rewrite of this script, you may want to ignore the
archived
subdirectory, and usemv -n -t
. You also need to explicitly-print
the found files (or usemv -v
) asfind
will otherwise not output their location:A few things from the comments (below) that may be useful to know:
If GNU
mv
is used with-t target
, it will fail iftarget
is not a directory. You would use-exec mv -t /opt/alfresco/archived/2020-01-07 {} +
to move multiple files at once withfind
(which would also speed up the operation).If GNU
mv
is used with-n
, it will refuse to overwrite existing files.Neither
-t
nor-n
are standard (macOS and FreeBSD have-n
too though), but that shouldn't stop you from using them in scripts that don't need to be portable between systems.