using find but only in subdirectories matching certain pattern - linux

I am trying to construct my etags file. I have a project structure such that given a root directory there are subdirectories and within those can be directories named 'cpp'. For example:
root
- sub1
- cpp
- sub2
- sub21
- cpp
- csharp
So for regular project i usually something like:
find . -type f ( -iname '.cpp' -o -iname '.hpp' -o -iname '.c' -o -iname '.h' -o -iname '.cc' -o -iname '.hh' ) -print | xargs etags -a
This won't work anymore as it will also pick up files that could be csharp, objective c etc...
So what i am trying to accomplish is to only have find return the files in the subdirectories called cpp. So how can i get find to do that?
Thanks ...

Or more simply (assuming there are not further subdirectories in the cpp directories:
find . -type f -path "*/cpp/*"
This would return the whole relative path from . though, which may require further trimming :/

Nested find might work for you
find . -type d -name "cpp" -exec find {} -type f \;

Related

Bash: Find files containing a certain string and copy them into a folder

What I want:
In a bash script: Find all files in current directory that contain a certain string "teststring" and cop them into a subfolder "./testfolder"
Found this to find the filenames which im looking for
find . -type f -print0 | xargs -0 grep -l "teststring"
..and this to copy found files to another folder (here selecting by strings in filename):
find . -type f -iname "stringinfilename" -exec cp {} ./testfolder/ \;
Whats the best way to combine both commands to achieve what I described at the top?
Just let find do both:
find . -name subdir -prune -o -type f -exec \
grep -q teststring "{}" \; -exec cp "{}" subdir \;
Note that things like this are much easier if you don't try to add to the directory you're working in. In other words, write to a sibling dir instead of writing to a subdirectory. If you want to wind up with the data in a subdir, mv it when you're done. That way, you don't have to worry about the prune (ie, you don't have to worry about find descending into the subdir and attempting to duplicate the work).

Is there a way to specify exceptions to exclusions in the find command via Bash?

I would like to find all of the files within a directory and its subdirectories except for any settings files and anything in settings or dependency directories.
For example, I want to exclude from my results entire directories like .git, .idea, and node_modules as well as files like .DS_Store and config.codekit, but I want to include .gitignore.
What I want is something like the results of the following Git command, but including any untracked files and able to be easily and safely operated upon (e.g., to change permissions).
git ls-tree -r master --name-only
Here is what I have so far and although it is rather unwieldy it seems to mostly do what I want except for leaving out .gitignore:
find . -type f -not -name ".*" -not -name config.codekit -not -path "./.*" -not -path "./node_modules/*"
I have experimented with -prune without much success.
Is there a way to specify exceptions to exclusions in the find command via Bash—to say something like exclude all the things that match this pattern EXCEPT this thing or these things?
By the way, I am presently using OS X, but I also use Ubuntu and I plan to try Ubuntu on Windows when the Windows 10 Anniversary Update is generally available, so ideally I would like to have a command that works across all of those.
Thank you in advance for any solutions, insights, or optimizations!
Update
Thanks to help from gniourf-gniourf, I have revised my command. This seems to do what I wanted:
find . -type f \( \! -name ".*" \! -name config.codekit \! -path "./.*" \! -path "./node_modules/*" -o -name .gitignore \)
A quick example first: to find all files, pruning the .git directories and ignoring the .DS_Store files:
find . -name .git -type d \! -prune -o \! -name .DS_Store -type f
For example, I want to exclude from my results entire directories like .git, .idea, and node_modules as well as files like .DS_Store and config.codekit, but I want to include .gitignore.
find . \( -name .git -o -name .idea -o -name node_modules \) -type d \! -prune -o \! -name .DS_Store \! -name config.codekit -type f
When building your command, make sure you stick with the POSIX standard: it's a guarantee that your command will work on any (POSIX compliant) system. For example, -not is not POSIX compliant: use ! instead (you'll have to escape it so as to not clash with your shell history expansion).
Is there a way to specify exceptions to exclusions in the find command via Bash—to say something like exclude all the things that match this pattern EXCEPT this thing or these things?
Find files, excluding everything (pattern *) except the files one and two:
find . \( \! -name '*' -o -name one -o -name two \) -type f

Find all files contained into directory named

I would like to recursively find all files contained into a directory that has name “name1” or name “name2”
for instance:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name1/subfolder/file1s.a
structure/of/dir/name1/subfolder/file2s.b
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
structure/of/dir/name2/subfolder/file1s.a
structure/of/dir/name2/subfolder/file2s.b
structure/of/dir/name3/name1.a ←this should not show up in the result
structure/of/dir/name3/name2.a ←this should not show up in the result
so when I start my magic command the expected output should be this and only this:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
I scripted something but it does not work because it search within the files and not only folder names:
for entry in $(find $SEARCH_DIR -type f | grep 'name1\|name2');
do
echo "FileName: $(basename $entry)"
done
If you can use the -regex option, avoiding subfolders with [^/]:
~$ find . -type f -regex ".*name1/[^/]*" -o -regex ".*name2/[^/]*"
./structure/of/dir/name2/file1.a
./structure/of/dir/name2/file3.c
./structure/of/dir/name2/subfolder
./structure/of/dir/name2/file2.b
./structure/of/dir/name1/file1.a
./structure/of/dir/name1/file3.c
./structure/of/dir/name1/file2.b
I'd use -path and -prune for this, since it's standard (unlike -regex which is GNU specific).
find . \( -path "*/name1/*" -o -path "*/name2/*" \) -prune -type f -print
But more importantly, never do for file in $(find...). Use finds -exec or a while read loop instead, depending on what you really need to with the matching files. See UsingFind and BashFAQ 20 for more on how to handle find safely.

Alternative way to find all files in a folder and subfolders

Is there any alternative for below command to find files in a folder and subfolders as well.
find . | egrep '\./[^/]+/[^/]+/[^/]+'
Note: I don't want directories I want to get only files
Additionally, you could specify list of files extensions as your search options:
find . -type f -name "*.js" -o -name "*.ros" -o -name "*.php"
Above example, would only display file names with *.ros, *.php, and *.js as file extensions under specific folder and subfolders.
Why don't you just use find?
I am not sure from your question if you want to limit the depth. If so:
find . -type f -depth 2 -print
If you just want to find files
find . -type f -print
If you just want to find directories
find . -type d -print
You can also use -ls if -print does not float your boat.
find . -type f -ls

Output directory name from linux find command

How do I get the name of a folder from a linux find commnad.
I have a command like this:
find /root/wgetlog -name -type d -empty
Whic produces the following results:
/root/wgetlog/smil3
/root/wgetlog/smil5
/root/wgetlog/smil4
how do I get just the name of the folder:
Example:
smil3
smil4
smil5
find /root/wgetlog -type d -empty -printf "%f\n"
If all you need is a relative path, then
{ pushd /root/wgetlog/; find . -name -type d -empty; popd; }
is the approach, especially if you do care about subdirectories of /root/wgetlog/*.
Use basename:
find /root/wgetlog -type d -empty -exec basename {} \;
You don't need -name.
You could also use sed to filter out the leading elements of each path:
$ find /usr/bin -type d
/usr/bin
/usr/bin/multiarch-i386-linux
/usr/bin/multiarch-x86_64-linux
/usr/bin/gda_trml2pdf
/usr/bin/gda_trml2html
...
$ find /usr/bin -type d | sed 's|.*/||'
bin
multiarch-i386-linux
multiarch-x86_64-linux
gda_trml2pdf
gda_trml2html
...
This might be more portable than using the -printf option of find, although that should not be an issue if you stick to Linux.
Disclaimer: this will fail horribly if you have newlines in your file/folder names. On the other hand, this snippet is probably not the only thing that would fail in that case...

Resources