Combine two find commands - bash

I'm looking to find the folder named - secrets, under /home/build, if found, check if it has a tar.gz file under it, recursively.
I tried some thing like below but it didn't work, how can I fix this ?
find -type d \( -name "secrets" \) -exec find . -type f -name "*.tar.gz"
OS - MacOS

this should work :
find -type d \( -name "secrets" \) -execdir find {} -type f -name "*.tar.gz" \;

Related

Need to find files with multiples arguments in bash

I've done this atm, I need to find in the main directory and in the sub-directory everything starting with the letter 'a', every files ending with 'z' and every files starting with 'z' and ending with 'a!'.
find . -name "a*" | find . "*z" -type f | find . "z*a!" -type f
I tried to be as clear as possible, sorry if it wasn't clear enough.
find . -type f \( -name 'a*' -or -name '*z' -or -name 'z*a!' \)
Use -o instead of -or for POSIX compliance.
If you really want to also find links, directories, pipes etc. starting with a but only files matching the remaining conditions, you can do
find . -name 'a*' -or -type f \(-name '*z' -or -name 'z*a!' \)
TL;DR
find . -name 'a*' -o -type f \( -name '*z' -o -name 'z*a!' \)
Explanations:
The find logical operators are -a (AND) and -o (OR). You use them to combine elementary tests. Note that because of operator's precedence you sometimes need parentheses and that they must be escaped (with \) to prevent their interpretation by the shell. Your test is:
everything starting with the letter 'a': -name 'a*'.
every files ending with 'z': -type f -a -name '*z'.
every files starting with 'z' and ending with 'a!': -type f -a -name 'z*a!'.
So the complete test could be:
-name 'a*' -o \( -type f -a -name '*z' \) -o \( -type f -a -name 'z*a!' \)
As -a is the default we can omit it, and as -type f (file) is common to the two last terms of the disjunction we can factor it:
-name 'a*' -o -type f \( -name '*z' -o -name 'z*a!' \)

In BASH, find folders that match different names

I would like to find all my sub-folders that match with different names and that are older than X days
I tried with just one name:
find my_folder -maxdepth 3 -type d -name "*mine*" -mtime +30
This works ok. I don't know how to extend this in order to match also folders with "test" and "older" names
You can use -o to OR the conditions and make sure to use parentheses around ORed directives:
find my_folder -maxdepth 3 -type d \( -name "*mine*" -o -name "*test*" -o -name "*older*" \) -mtime +30
Another alternative is using -regex option:
find my_folder -regextype posix-extended -maxdepth 3 -type d -regex '.*(minetest|older).*" -mtime +30

Bash/Shell Combine options using find

Using the find command is there a way to combine options:
i.e.
find . -type fd -name "somefile"
Although -type ignores the second option; I'm looking to find only files or directories.
You can use -o for OR condition in find:
find . \( -type d -o -type f \) -name "somefile"

Find and delete old files excluding some subdirectories

I have been searching for a while, but can't seem to get a succinct solution. I am trying to delete old files but excluding some subdirectories (passed via parm) and their child subdirecories.
The issue that I am having is that when the subdirectory_name is itself older than the informed duration (also passed via parm) the find command is including the subdirectory_name on the list of the find. In reality the remove won't be able to delete these subdirectories because the rm command default option is f.
Here is the find commmand generated by the script:
find /directory/ \( -type f -name '*' -o -type d \
-name subdirectory1 -prune -o -type d -name directory3 \
-prune -o -type d -name subdirectory2 -prune -o \
-type d -name subdirectory3 -prune \) -mtime +60 \
-exec rm {} \; -print
Here is the list of files (and subdirectories brought by the find command)
/directory/subdirectory1 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory2 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory3 ==> this is a subdreictory name and I'd like to not be included
/directory/subdirectory51/file51
/directory/file1 with spaces
Besides this -- the script works fine not bringing (excluding) the files under these 3 subdirectories:
subdirectory1, subdirectory2 and subdirectory3.
Thank you.
Following command will delete only files older than 1 day.
You can exclude the directories as shown in the example below, directories test1 & test2 will be excluded.
find /path/ -mtime +60 -type d \( -path ./test1 -o -path ./test2 \) -prune -o -type f -print0 | xargs -0 rm -f
Though it would be advisable to see what's going to be deleted using -print
find /path/ -mtime +60 -type d \( -path ./test1 -o -path ./test2 \) -prune -o -type f -print
find /directory/ -type d \(
-name subdirectory1 -o \
-name subdirectory2 -o \
-name subdirectory3 \) -prune -o \
-type f -mtime +60 -print -exec rm -f {} +
Note that the AND operator (-a, implicit between two predicates if not specified) has precedence over the OR one (-o). So the above is like:
find /directory/ \( -type d -a \(
-name subdirectory1 -o \
-name subdirectory2 -o \
-name subdirectory3 \) -a -prune \) -o \
\( -type f -a -mtime +60 -a -print -a -exec rm -f {} + \)
Note that every file name matches the * pattern, so -name '*' is like -true and is of no use.
Using + instead of ; runs fewer rm commands (as few as possible, and each is passed several files to remove).
Do not use that code above on directories writeable by others as it's vulnerable to attacks whereby the attacker can change a directory to a symlink to another one in between the time find traverses the directory and calls rm to have you delete any file on the filesystem. Can be alleviated by changing the -exec part with -delete or -execdir rm -f {} \; if your find supports them.
See also the -path predicate if you want to exclude a specific subdirectory1 instead of any directory whose name is subdirectory1.

Redirect output from -exec in find command to variable

I have a command in the form:
find -name *.* -type f -exec rm {} -v \;
And I want to get the list of files that it processed into a variable. How would I do that in ksh?
VAR=`find /dir -name '*.*' -type f -print -exec rm {} \;`
Append a "-print" after your arguments
Here's an example:
VAR=$(your statement)
I'm not a ksh-user, so I might be wrong. In bash, I have to mask the asteriks:
find -name "*.*" -type f -exec rm {} -v \;
and I can use -delete instead of -exec rm, but delete is special for GNU-find:
find -name "*.*" -type f -delete
and to output the file names, append a print:
find -name "*.*" -type f -delete -print
and capture the output
deleted=$(find -name "*.*" -type f -delete -print)

Resources