Shell script to list all subdirectories recursively within a folder that contains files with an specific extension - linux

I have a folder named a, and it may have one or multiple sub-directories and the sub-directories may have multiple sub-directories and so on. I want to know how can I write a shell script to list all the sub-directories that contain a file with specific extension.
So, it may be like
A -> B -> C
-> D -> f2.txt
-> F -> f3.txt
-> E -> G -> H -> f4.txt
So only D, F and H directories will be listed. Actually I need this as a quick way to find the package names of particular java classes, by listing their directory tree. For example in the previous example A.E.G.H is a package same as A.D, but A.E.G is not a package as G only contains a sub directory H no files.

I think you need find command. You can use like this,
find . -name '*.txt'
Here,
. - dot(.) is current directory. You can also specify the path where to start.
-name - file name to find.
You can also use -maxdepth option to limit the depth of recursive finding. Normally, find will find the file recursively.
Update:
If you want to list out the directories,
find . -name '*.txt' -exec dirname {} \;

find . -name '*.txt' -printf '%h\n'
man find will give other possible format flags usable with -printf

A simpler and faster alternative for systems like MAC. No need to use 2 additional tools and even repeatingly call dirname:
find -type f -name '*.txt' | awk 'BEGIN{FS=OFS="/"}{--NF}!a[$0]++'
-type f may be removed optionally if it doesn't work.

Related

Find leaf directories contained within directories matching a wildcard

The following works very well. It gets me leaf directories.
find . -type d -links 2
What I need is something like below. In the current directory, there are directories named as C2S7*, within those I need the leaf directories.
find . -name "C2S7*" -type d -links 2
The above looks for the wildcard in the leaf directory names as well. What is the alternative?
To look inside direct children matching the pattern:
find C2S7*/ -type d -links 2
To look inside direct or indirect children matching the pattern:
find . -path "*/C2S7*/*" -type d -links 2
Specification.

Bash Command for Finding the size of all files with particular filetype in a directory in ubuntu

I have a folder which contains several file types say .html,.php,.txt etc.. and it has sub folders also .Sub folders may contain all the file types mentioned above.
Question1:- I want to find size of all the files having the file type as '.html' which are there in both root directory and in sub- directories
Question2:- I want to find size of all the files having the file type as '.html' which are there only in root directory but not in sub folders.
I surfed through the internet but all i am able to get is commands like df -h, du -sh etc..
Are there any bash commands for the above questions? Any bash scripts?
You can use the find command for that.
#### Find the files recursively
find . -type f -iname "*.html"
#### Find the files on the r
find . -type f -maxdepth 1 -iname "*.iml"
Then, in order to get their size, you can use the -exec option like this:
find . -type f -iname "*.html" -exec ls -lha {} \;
And if you really only need the file size (I mean, without all the other stuff that ls prints):
find . -type f -iname "*.html" -exec stat -c "%s" {} \;
Explanation:
iname search of files without being case sensitive
maxdepth travels subdirectories recursively up to the specify level (1 means only the immediate folder)
exec executes an arbitrary command using the found paths, where "{}" represents the path of the file
type indicates the type of file (a directory is a file in Linux)

Find command ignore directory

I am trying to find all files ending in .jar, but it is picking up folders that ends in .jar which is something I do not want.
My command so far
find . -name ".*jar"
I need it so it ignores directories ending in .jar
Additional request.
I now need to ignore a specific folder when looking, is this possible?
Thanks.
just add -type f:
find . -name "*.jar" -type f
Others have already shown, how to pick up files named ending in .jar. As an answer to your comment "How to ignore a specific folder". You use -prune for that
find . -name 'specific/folder' -type d -prune -o -type f -name '*.jar'
that's what you want
find . -type f -name "*.jar"
see man page:
-type Type
Evaluates to the value True if the Type variable specifies one of the following values:
b
Block special file
c
Character special file
d
Directory
f
Plain file
l
Symbolic link
p
FIFO (a named pipe)
s
Socket

how to exclude few folder levels in the FIND command results - unix

Following is the folder structure
- home/ABCD/test1/example1/sample1/textfile.txt
If I execute the find command like
find /home/ABCD/ -type f -print
I am getting the following output
/home/ABCD/test1/example1/sample1/textfile.txt
Note: I am executing the find command from the ABCD folder, In the results I want to exclude /home/ABCD/ folder I just want /test1/example1/sample1/testfile.txt as the result
How can I achieve this?
Since you are executing find from /home/ABCD/ do something like this:
find * -type f -print
Or if you are looking for files in test1 do this:
find test1 -type f -print
Also with -maxdepth N you can limit the recursion in find
If you only want to look for files named textfile.txt do
find test1 -type f -name 'textfile.txt' -print
If you want to print the leading slash do
find . -type f -printf '/%p\n'
For more info have a look here
Note: If have the above string in a variable, you can trim it like this:
string="/home/ABCD/test1/example1/sample1/textfile.txt"
echo "${string#/home/ABCD}"
Some more examples of string manipulation here
Just use . as the starting directory
find . -type f -print
gives
./test1/example1/sample1/textfile.txt
and if you really want a leading slash, use -printf for the output
find . -type f -printf '/%P\n'
You can use the mindepth parameter to start looking at one level below the current directory
find /home/ABCD/ -mindepth 1 -type f -print
This should substitute your current working directory name with a .
find . -type f | perl -pne "s#$PWD#.#"
So you would get results like:
./test1/example1/sample1/textfile.txt
If you do not want the preceeding ./, use this command instead:
find . -type f | perl -pne "s#$PWD/##"

Find Directories With No Files in Unix/Linux

I have a list of directories
/home
/dir1
/dir2
...
/dir100
Some of them have no files in it. How can I use Unix find to do it?
I tried
find . -name "*" -type d -size 0
Doesn't seem to work.
Does your find have predicate -empty?
You should be able to use find . -type d -empty
If you're a zsh user, you can always do this. If you're not, maybe this will convince you:
echo **/*(/^F)
**/* will expand to every child node of the present working directory and the () is a glob qualifier. / restricts matches to directories, and F restricts matches to non-empty ones. Negating it with ^ gives us all empty directories. See the zshexpn man page for more details.
-empty reports empty leaf dirs.
If you want to find empty trees then have a look at:
http://code.google.com/p/fslint/source/browse/trunk/fslint/finded
Note that script can't be used without the other support scripts,
but you might want to install fslint and use it directly?
You can also use:
find . -type d -links 2
. and .. both count as a link, as do files.
The answer of Pimin Konstantin Kefalou prints folders with only 2 links and other files (d, f, ...).
The easiest way I have found is:
for directory in $(find . -type d); do
if [ -n "$(find $directory -maxdepth 1 -type f)" ]; then echo "$directory"
fi
done
If you have name with spaces use quotes in "$directory".
You can replace . by your reference folder.
I haven't been able to do it with one find instruction.

Resources