shell find command : Mixing excluding directories and including specific directories - shell

I'm faced with a directory structure like :
./xxx/src
./xxx/src/folder1
./xxx/src/folder2
./xxx/src/folder2/subfolder1
./xxx/UTest
./xxx/Module
./xxx/Itfs
./.hg
./Tools
Instead of having each module define it's own include search directory. I want to find all relevant directories with a "simple" shell command and use this in my top level makefile.
That would look alot nicer and as bonus, force other users to use folders defined in the coding guidelines.
I got as far as :
MODINCLUDES = \
$(shell find $(MODULE_DIR) \( -name .hg -o -name Tools \) -prune -o \( -name src -o -name Module -o -name Itfs \) -type d -print| while read line; do echo "-I$$line"; done )
But this would result in
MODINCLUDES = -I/xxx/src -I/xxx/Module -I/xxx/Itfs
Obviously I would like have any subfolders in src to be included aswell.
./xxx/src/folder1
./xxx/src/folder2
./xxx/src/folder2/subfolder1
Can someone explain me, on how to do this ?
Thanks !

If I understand your question correctly, just don't restrict to just the three specific folders. Take out the
\( -name src -o -name Module -o -name Itfs \)
and maybe avoid the silly while loop if your find supports -printf:
MODINCLUDES = \
$(shell find $(MODULE_DIR) \
\( -name .hg -o -name Tools \) -prune -o \
-type d -printf "-I%p\n")

Finding the sub-directories you want with find can be done with:
find $(MODULE_DIR)/xxx/src $(MODULE_DIR)/xxx/Module $(MODULE_DIR)/xxx/Itfs -type d
And then, putting this in a Makefile and adding the -I prefix:
ROOTDIRS := $(addprefix $(MODULE_DIR)/xxx/,src Module Itfs)
SUBDIRS := $(shell find $(ROOTDIRS) -type d)
MODINCLUDES := $(addprefix -I,$(SUBDIRS))
Or, all at once:
MODINCLUDES := $(addprefix -I,$(shell find $(addprefix $(MODULE_DIR)/xxx/,src Module Itfs) -type d))

Related

find and delete folder and/or zip file in a directory [duplicate]

I was trying to get a list of all python and html files in a directory with the command find Documents -name "*.{py,html}".
Then along came the man page:
Braces within the pattern (‘{}’) are not considered to be special (that is, find . -name 'foo{1,2}' matches a file named foo{1,2}, not the files foo1 and foo2.
As this is part of a pipe-chain, I'd like to be able to specify which extensions it matches at runtime (no hardcoding). If find just can't do it, a perl one-liner (or similar) would be fine.
Edit: The answer I eventually came up with include all sorts of crap, and is a bit long as well, so I posted it as an answer to the original itch I was trying to scratch. Feel free to hack that up if you have better solutions.
Use -o, which means "or":
find Documents \( -name "*.py" -o -name "*.html" \)
You'd need to build that command line programmatically, which isn't that easy.
Are you using bash (or Cygwin on Windows)? If you are, you should be able to do this:
ls **/*.py **/*.html
which might be easier to build programmatically.
Some editions of find, mostly on linux systems, possibly on others aswell support -regex and -regextype options, which finds files with names matching the regex.
for example
find . -regextype posix-egrep -regex ".*\.(py|html)$"
should do the trick in the above example.
However this is not a standard POSIX find function and is implementation dependent.
You could programmatically add more -name clauses, separated by -or:
find Documents \( -name "*.py" -or -name "*.html" \)
Or, go for a simple loop instead:
for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
This will find all .c or .cpp files on linux
$ find . -name "*.c" -o -name "*.cpp"
You don't need the escaped parenthesis unless you are doing some additional mods. Here from the man page they are saying if the pattern matches, print it. Perhaps they are trying to control printing. In this case the -print acts as a conditional and becomes an "AND'd" conditional. It will prevent any .c files from being printed.
$ find . -name "*.c" -o -name "*.cpp" -print
But if you do like the original answer you can control the printing. This will find all .c files as well.
$ find . \( -name "*.c" -o -name "*.cpp" \) -print
One last example for all c/c++ source files
$ find . \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) -print
I had a similar need. This worked for me:
find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
My default has been:
find -type f | egrep -i "*.java|*.css|*.cs|*.sql"
Like the less process intencive find execution by Brendan Long and Stephan202 et al.:
find Documents \( -name "*.py" -or -name "*.html" \)
Braces within the pattern \(\) is required for name pattern with or
find Documents -type f \( -name "*.py" -or -name "*.html" \)
While for the name pattern with and operator it is not required
find Documents -type f ! -name "*.py" -and ! -name "*.html"
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done
simple but works :)
I needed to remove all files in child dirs except for some files. The following worked for me (three patterns specified):
find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
This works on AIX korn shell.
find *.cbl *.dms -prune -type f -mtime -1
This is looking for *.cbl or *.dms which are 1 day old, in current directory only, skipping the sub-directories.
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
What about
ls {*.py,*.html}
It lists out all the files ending with .py or .html in their filenames

How to escape backslash in makefile shell function

I need to recursively find all the header files in a list of directories. I can't figure out how to escape the command properly. I have searched around and found various information on escaping in makefiles but I have not been able to solve this issue.
In bash the following does what I want:
find path1 path2 path3 -type f \( -name *.hpp -o -name *.h -o *.hxx \)
In my make file I have tried a few combinations of foreach, etc. Currently I have this:
INCLUDE_PATHS ?= path1 path2 path3
MY_HEADERS := $(shell find $(INCLUDE_PATHS) -type f \( -name *.h -o -name *.hpp -o -name *.hxx \))
This produces:
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]
If I just look for one extension such as "*.hpp" it works fine (I assume because the \(...\) is not needed).
I have tried various combinations of $, ', ". \ to escape the '\' characters in the shell command without success.
Any help would be greatly appreciated.
Your problem doesn't have anything to do with make or the value of INCLUDE_PATHS or how make interprets backslash characters. The problem is that you're not escaping your globbing, and it's matching some local files. Rewrite your function to escape your glob statements, like this:
MY_HEADERS := $(shell find $(INCLUDE_PATHS) -type f \( -name \*.h -o -name \*.hpp -o -name \*.hxx \))
I would be very surprised if the original command works in bash without quoting those characters, if you run it from the same directory containing the same contents as make.
The variable MY_HEADERS becomes correct, by calling $($INCLUDE_PATHS) -- not $(INCLUDE_PATHS).
So your Makefile would be:
INCLUDE_PATHS ?= path1 path2 path3
MY_HEADERS := $(shell find $($INCLUDE_PATHS) -type f \( -name *.h -o -name *.hpp -o -name *.hxx \))
You can continue to check the variable's value:
all: printme
printme:
#echo $(MY_HEADERS)
Running this Makefile by make will show your desired answer.
Although MadScientist already answered the question perfectly, you could use the following to avoid the shell altogether:
INCLUDE_PATHS ?= path1 path2 path3
EXTENSIONS := .h .hpp .hxx
MY_HEADERS := $(shell find $(INCLUDE_PATHS) -type f \( -name \*.h -o -name \*.hpp -o -name \*.hxx \))
$(info $(MY_HEADERS))
MY_HEADERS := $(foreach p,$(INCLUDE_PATHS),$(foreach e,$(EXTENSIONS),$(wildcard $(p)/*$(e))))
$(info $(MY_HEADERS))

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.

find with keywords but skip folders

I'm using the following command to find specific file extensions within folders,sub-sub-sub folders etc. However, it also return results if a folder/directory that has that particular keyword as well. How can I bypass this?
find . \( -type d -a ! -name 'downloading' -a ! -name 'vntdone' -a ! -name '.' \) -o -name \*.avi -o -name \*.mkv -o -name \*.mp4 -o -name \*.VOB
Any kind of help I can get on this is greatly appreciated! Thank you.
I am not quite sure I understand the need for your first parameters, but is this what you're looking for?
find . -type f \( -name \*.avi -o -name \*.mkv -o -name \*.mp4 -o -name \*.VOB \)
This will output files names ending with avi, mkv, mp4 and VOB

In Ksh Shell use FIND to search through symbolic links but ignore certain directories

I am trying to search for *.csv files in file system. There are symbolic links in certain directories that i am looking through, but i want to ignore certain directories since they result in nasty long time consuming cycles.
find -L "location" -name "*.csv >> find_result.txt
How can i tell find to ignore certain directories while keep looking at symbolic links in others.
Use -prune to tell find not to descend into a given directory. For instance:
find -L location -name 'dontLookHere' -prune \
-o -name 'orThereEither' -prune \
-o -name '*.csv' -print
find dir -wholename dirtoskip -prune -o [rest of your find command]
or
find dir \( -wholename dirtoskip -o -wholename another \) -prune -o [rest of your find command]

Resources