Find error - unknown primary or operator - bash

find /Volumes/COMMON-LIC-PHOTO/STAGING/Completed -type d -maxdepth 2 -iname -iregex '.*_OUTPUT' -exec rsync -rtWv --stats --progress {} /Volumes/COMMON-LIC-PHOTO/ASPERA/ASPERA_STAGING/ \;
The code above is designed to look inside the directory Complete for any sub-directories with the phrase "_OUTPUT" (ignoring case, hence -iname) at the end of the directory name and copy what it finds to a new location, Aspera_Staging. I'm running the code in a .sh triggered by the launchcd app Launch Control whenever a new directory is moved to Complete (which could be part of the issue because cron seems to be very picky).
It works about half the time, the other half it does nothing at all. An OUTPUT directory won't be copied. I can't find a pattern, it almost seems random. I've noticed in the debug log that it is giving me the following error:
find: .*_OUTPUT: unknown primary or operator
I've spent hours tinkering, trying to figure it out. I've followed a lot of suggestions found on here and other sites but so far nothing has worked. It obviously has something to do with it looking for the Output folders but I just can't get to the bottom of it.

As commenters have noticed, -iname requires a parameter, therefore the -iregex that follows is understood as that parameter and the parameter to -iregex is (mis)taken as an operator, hence your error message.
In your context, -iname and -iregex seem redundant, so your command should be either:
find /Volumes/COMMON-LIC-PHOTO/STAGING/Completed -type d -maxdepth 2 -iname '*_OUTPUT' -exec ... \;
or:
find /Volumes/COMMON-LIC-PHOTO/STAGING/Completed -type d -maxdepth 2 -iregex '.*_OUTPUT' -exec ... \;
(notice how the parameters to -iname and to -iregex slightly differ)

Related

Trying to find files containing an identifier, then move them to a new directory within terminal

I'm a beginner with this stuff and seem to be running into an issue.
Basically, I have many files with names containing a keyword (let's call it "Category1") within a directory. For example:
ABC-Category1-XYZ.txt
I'm trying to move them from a directory into another directory with the same name as the keyword.
I started with this:
find /path_A -name "*Category1*" -exec mv {} /path_A/Category1 \;
It spit out something like this:
mv: rename /path_A/Category1 to /path_A/Category1/Category1: Invalid
Argument
So I did some fiddling and hypothesized that the problem was caused by the command trying to move the directory Category1 into itself(maybe). I decided to exclude directories from the search so it would only attempt to move files. I came up with this:
find /path_A -name "*Category1*" \(! -type d \) -exec mv {} /path_A/Category1 \;
This did move the files from their original location to where I wanted them, but it still gave me something like:
mv: /path_A/Category1/ABC-Category1-XYZ.txt and
/path_A/Category1/ABC-Category1-XYZ.txt are identical
I'm no expert, so I could be wrong... but I believe the command is trying to find and move the files from their original directory, then find them again. The directory Category1 is a subdirectory of the starting point, /path_A, So i believe it is finding the files it just moved in the directory Category1 and attempting to move them again.
Can anyone help me fix this issue?
You are creating new files that find tries to process. Safest approach is to move them somewhere else not in the path_A you are searching with find.
Or you can use prune to ignore that directory if you don't have any other directory matching:
find /path_A -name '*Category1*' -prune -type f -exec mv {} /path_A/Category1/ \;
Although another post has been accepted, let me post a proper answer.
Would you please try:
find /path_A -name 'Category1' -prune -o -type f -name '*Category1*' -exec mv -- {} /path_A/Category1/ \;
The option -prune is rather a command than a condition. It tells find to
ignore the directory tree specified by the conditions before -prune.
In this case it excludes the directory Category1 from the search.
The following -o is logical OR and may be interpreted something like instead or else. The order of the options makes difference.
Please be noticed the 1st category1 is the directory name to exclude and the 2nd *Category1* is the filenames to find.
If you are not sure which files are the result of find, try to execute:
find /path_A -name 'Category1' -prune -o -type f -name '*Category1*' -print
then tweak the options to see the change of output.

Why can't I exclude a directory using find

I attempting to run a command on all subdirectories in a directory using find and -exec, however on one of the directories, the user the script runs under does not have adequate permissions and I get an error (permission denied). I am attempting to ignore the directory using either ! -path or using -prune. Neither of these methods work. I have tried both of the commands down below.
I have tried every combination of subDirToExclude— with and without ./ at the beginning, with and without /* at the end. I've tried relative path, full path and every single combination of all of them that you can think of to try and match this path, but it simply does not work. The man page is unhelpful and no suggestions from any related questions on this forum produce any useful results. Why do none of the methods suggested in the man page work? How can this actually be done?
find /path/to/dir -maxdepth 1 -type d ! -path "subDirToExclude" -exec somecommand {} +
find /path/to/dir -maxdepth 1 -type d -path "subDirToExclude" -prune -o -exec somecommand {} +
find: ‘/path/to/dir/subDirToExclude’: Permission denied
The argument to the -path option should be a full pathname, not just the name of the directory. Use -name if you just want to match the name of the directory.
find /path/to/dir -maxdepth 1 -type d ! -name "subDirToExclude" -exec somecommand {} +
You could also do this without using find at all, since you're not recursing into subdirectories because of -maxdepth 1.
shopt -s extglob
somecommand /path/to/dir /path/to/dir/!(subDirToExclude)/
Putting / at the end of the filename makes the wildcard only match directories. Actually, this will also match symbolic links to directories; if that's a problem, you can't use this solution.

BASH; using find and -exec to remove .pyc files

Using the command line in Ubuntu 16.04.2 LTS. I'm getting towards the end of Zed Shaw's LPTHW, and on the video to ex46.py he exercises the following bash command to find and remove all .pyc byte code files:
find . -name "*.pyc" -exec rm {}
On the video this successfully removes all of Zed Shaw's .pyc files. However, upon typing in the exact same command I get the following error:
find: missing argument to `-exec'
I understand that there are many ways to delete .pyc files, however, since I'm following along with Zed Shaw I'd like to know how to do it using find and -exec. What am I doing wrong?
you need to terminate the -exec command with \;
find . -name "*.pyc" -exec rm {} \;
have a look at find -exec in the man page.
as mentioned in the comments by Gordon Davisson it may be more efficient to terminate the command with + as rm is then invoked fewer times:
find . -name "*.pyc" -exec rm {} +
You could leverage using -delete over -exec rm as the former does not spawn a new process for each of the file instance to delete. Also you could chip in the -type f option to apply the operation for files only.
find . -type f -name "*.pyc" -delete

Error = find: -exec: no terminating ";" or "+"

I am looking for some help trying to get a command working. I want to find some files only and move them, but when I enter this command:
find /Volumes/NEXSAN/Engine\ Folders/Input/DTO_Proxy/* -type f -mtime +7 -exec mv -v {} /Volumes/NEXSAN/.2BeDeleted4realz/
I get this error
find: -exec: no terminating ";" or "+"
I know I probably have it wrong, but I can't figure out what's missing?
Just terminate the find command with \;, making sure to include the space before the \;.
find /Volumes/NEXSAN/Engine\ Folders/Input/DTO_Proxy/* -type f -mtime +7 -exec mv -v {} /Volumes/NEXSAN/.2BeDeleted4realz/ \;
If you want to correct the find command that you had, it should look like this:
find . -name '*.xml' -exec SetFile -t TEXT {} \;
The *.xml needs to be quoted so it's passed as a parameter to find instead of expanded by the shell. The ; also needs to be escaped so it's passed as part of the parameter to find and not interpreted by the shell.
Keep in mind this will only work for files within the current directory (and subdirectories) and for any new files created, you would need to run the command again.

Exclude specified directory when using `find` command

I have a directory which contains a number of files (no subdirectories). I wish to find these files. The following gets me close:
$ find docs
docs
docs/bar.txt
docs/baz.txt
docs/foo.txt
I don't want the directory itself to be listed. I could do this instead:
$ find docs -type f
docs/bar.txt
docs/baz.txt
docs/foo.txt
Using a wildcard seems to do the trick as well:
$ find docs/*
docs/bar.txt
docs/baz.txt
docs/foo.txt
My understanding is that these work in different ways: with -type, we're providing a single path to find, whereas in the latter case we're using wildcard expansion to pass several paths to find. Is there a reason to favour one approach over the other?
You have a UNIX tag, and you example has a *. Some versions of find have a problem with that.
If the directory has no subdirectories.
FYI.
Generally the first parms to find has to be a directory or a list of directories
find /dir1 /dir2 -print
Find is recursive - so it will follow each directory down listing every thing, symlinks, directories, pipes, and regular files. This can be confusing. -type delimits your search
find /dir1 /dir2 -type f -print
You can also have find do extra output example: have it rm files older than 30 days for example:
find /dir1 /dir2 -type f -mtime +30 -exec rm {} \;
Or give complete infomation
find /dir1 /dir2 -type f -mtime +30 -exec ls -l {} \;
find /dir1 /dir2 -type f -mtime +30 -ls # works on some systems
To answer your question: because find can be dangerous ALWAYS fully specify each directory , file type ,etc., when you are using a nasty command like rm. You might have forgotten your favorite directory is also in there. Or the one used to generate your paycheck. Using a wildcard is ok for just looking around.
Using *
find /path/to/files -type f -name 'foo*'
-- tics or quotes around strings with a star in them in some UNIX systems.
find docs -type f
will get you a listing of every non-directory file of every subdirectory of docs
find docs/*
will get you a listing of every file AND every subdirectory of docs

Resources