List directory contents recursively to given depth - directory

How can I list directory contents recursively, but only until a specified depth? I'm trying to do the equivalent of ls -R --depth 2 with unix tools.

Simply with find tool:
find . -maxdepth 2
-maxdepth levels
Descend at most levels (a non-negative integer) levels of directories
below the starting-points.

Related

Rename all subdirectories in csh shell

I'm using csh and I have a directory structure containing multiple sub-directories. I'm trying to rename all the directories and sub-directories but not the files inside these directories. So something like
From
topdir1
--dir11
--dir12
topdir2
--dir21
----dir211
--dir22
to
topdir1.test
--dir11.test
--dir12.test
topdir2.test
--dir21.test
----dir211.test
--dir22.test
I can list the directories with find . -maxdepth 3 -type d. I'm trying to use a foreach loop to rename them. So
foreach i (`find . -maxdepth 3 -type d`)
mv $i $i.test
end
But this doesn't work as once the top level directory is renamed, it cannot find the sub-directories, so it only renames the top level directories.
Any idea on how to go about this?
Thanks
How about reversing the find results so that the subdirectories are listed first?
foreach i (`find ./* -maxdepth 3 -type d | sort -r`)
mv $i $i.test
end
Sort will output the longest directory names last, using the -r (reverse) flag changes it so that the lowest directories will be listed first, and be renamed before their parent directories do.
Use the -depth option to find.
From the solaris man find page:
-depth Always true. Causes descent of the
directory hierarchy to be done so that
all entries in a directory are acted on
before the directory itself. This can
be useful when find is used with cpio(1)
to transfer files that are contained in
directories without write permission.
Why use a loop? Just let find do the work:
find . -depth -maxdepth 3 -type d -exec mv {} {}.test \;
That is not strictly portable (some implementations of find may legally not expand {}.test to the string you want, so you might prefer:
find . -depth -maxdepth 3 -type d -exec sh -c 'mv $0 $0.test' {} \;

find, excluding dir, not descending into dir, AND using maxdepth and mindepth

This is RHEL 5.6 and GNU find 4.2.27.
I am trying to exclude a directory from find, and want to make sure that directory isn't descended into. I've seen plenty of posts saying -prune will do this - and it does. I can run this command:
find . -type d -name "./.snapshot*" -prune -o -print
and it works. I run it through strace and verify it is NOT descending into .snapshot.
I also want to find directories ONLY at a certain level. I can use mindepth and maxdepth to do this:
find . -maxdepth 8 -mindepth 8 -type d
and it gives me all the dirs 8 levels down, including what's in .snapshot.
If I combine the prune and mindepth and maxdepth options:
find . -maxdepth 8 -mindepth 8 -type d \( -path "./.snapshot/*" -prune -o -print \)
the output is right - I see all the dirs 8 levels down except for what's in .snapshot, but if I run that find through strace, I see that .snapshot is still being descended into - to levels 1 through 8.
I've tried a variety of different combinations, moving the precedence parens around, reording expression components - everything that yields the right output still descends into .snapshot.
I see in the man page that -prune doesn't work with -depth, but doesn't say anything about mindepth and maxdepth.
Can anyone offer any advice?
Thanks...
Bill
I think this is your answer. -mindepth seems to turn off all test till that level. kind of a bummer.
(right from "man find")
-mindepth levels
**Do not apply any** tests or actions at levels less than levels (a non-negative integer).
'-mindepth 1' means process all files except the command line arguments.
I'm adding this as another answer because it's a different take on the issue. You could try the find command like this :
find * .[^s][^n]* (other switches/args)
It would avoid the .snapshot directory by using the shell instead of the find switches. granted it's not perfect but maybe it's close enough for what you are doing.

GNU find: Search in current directory first

how can I tell find to look in the current folder first and then continue search in subfolders? I have the following:
$ find . -iname '.note'
folder/1/.note
folder/2/.note
folder/3/.note
folder/.note
What I want is this:
$ find . -iname '.note'
folder/.note
folder/1/.note
folder/2/.note
folder/3/.note
Any ideas?
find's algorithm is as follows:
For each path given on the command line, let the current entry be that path, then:
Match the current entry against the expression.
If the current entry is a directory, then perform steps 1 and 2 for every entry in that directory, in an unspecified order.
With the -depth primary, steps 1 and 2 are executed in the opposite order.
What you're asking find to do is to consider files before directories in step 2. But find has no option to do that.
In your example, all names of matching files come before names of subdirectories in the same directory, so find . -iname '.note' | sort would work. But that obviously doesn't generalize well.
One way to process non-directories before directories is to run a find command to iterate over directories, and a separate command (possibly find again) to print matching files in that directory.
find -type d -exec print-matching-files-in {} \;
If you want to use a find expression to match files, here's a general structure for the second find command to iterate only over non-directories in the specified directory, non-recursively (GNU find required):
find -type d -exec find {} -maxdepth 1 \! -type d … \;
For example:
find -type d -exec find {} -maxdepth 1 \! -type d -iname '.note' \;
In zsh, you can write
print -l **/(#i).note(Od)
**/ recurses into subdirectories; (#i) (a globbing flag) interprets what follows as a case-insensitive pattern, and (Od) (a glob qualifier) orders the outcome of recursive traversals so that files in a directory are considered before subdirectories. With (Odon), the output is sorted lexicographically within the constraint laid out by Od (i.e. the primary sort criterion comes first).
Workaround would be find . -iname '.note' | sort -r:
$ find . -iname '.note' | sort -r
folder/.note
folder/3/.note
folder/2/.note
folder/1/.note
But here, the output is just sorted in reverse order and that does not change find's behaviour.
For me with GNU find on Linux I get both orderings with different test runs.
Testcase:
rm -rf /tmp/depthtest ; mkdir -p /tmp/depthtest ; cd /tmp/depthtest ; for dir in 1 2 3 . ; do mkdir -p $dir ; touch $dir/.note ; done ; find . -iname '.note'
With this test I get the poster's first result. Note the ordering of 1 2 3 .. If I alter this ordering to to . 1 2 3
rm -rf /tmp/depthtest ; mkdir -p /tmp/depthtest ; cd /tmp/depthtest ; for dir in . 1 2 3 ; do mkdir -p $dir ; touch $dir/.note ; done ; find . -iname '.note'
I get the poster's second result.
In either case adding -depth to find does nothing.
EDIT:
I wrote a perl oneliner to look in to this further:
perl -e 'opendir(DH,".") ; print join("\n", readdir(DH)),"\n" ; closedir(DH)'
And I ran this against /tmp/depthtest after running testcase 1 with these results:
.
..
1
2
3
.note
I ran it again after testcase 2 with these results:
.
..
.note
1
2
3
Which confirms that the results are in directory order.
The -depth option to find only controls whether e.g. ./1/.note is processed before or after ./1/, not whether ./.note or ./1/ is first, so the order of the results is purely based on directory order (which is mostly creation order).
It might be helpful to look at How do I recursively list all directories at a location, breadth-first? to learn how to work around this problem.
find -s . -iname ".note" doesn't help? or find . -iname '.note'|sort ?
Find in the current folder
find ./in_save/ -type f -maxdepth 1| more
==>73!

find without recursion

Is it possible to use the find command in some way that it will not recurse into the sub-directories? For example,
DirsRoot
|-->SubDir1
| |-OtherFile1
|-->SubDir2
| |-OtherFile2
|-File1
|-File2
And the result of something like find DirsRoot --do-not-recurse -type f will be only File1, File2?
I think you'll get what you want with the -maxdepth 1 option, based on your current command structure. If not, you can try looking at the man page for find.
Relevant entry (for convenience's sake):
-maxdepth levels
Descend at most levels (a non-negative integer) levels of direc-
tories below the command line arguments. `-maxdepth 0' means
only apply the tests and actions to the command line arguments.
Your options basically are:
# Do NOT show hidden files (beginning with ".", i.e., .*):
find DirsRoot/* -maxdepth 0 -type f
Or:
# DO show hidden files:
find DirsRoot/ -maxdepth 1 -type f
I believe you are looking for -maxdepth 1.
If you look for POSIX compliant solution:
cd DirsRoot && find . -type f -print -o -name . -o -prune
-maxdepth is not POSIX compliant option.
Yes it is possible by using -maxdepth option in find command
find /DirsRoot/* -maxdepth 1 -type f
From the manual
man find
-maxdepth levels
Descend at most levels (a non-negative integer) levels of directories below the starting-points.
-maxdepth 0
means only apply the tests and actions to the starting-points themselves.

Union, Intersection and Exclude with the FIND-command?

I need to manage lists with find-command. Suppose the lists have random names in non-distinct lists (ie their intersection is not empty set). How can I do:
A \ B
find files in the list A except the files in the list B
A intersection B
find files common to the lists A and B
Please, consult here.
A union B
find all files in the two lists
EXAMPLES
$ find . | awk -F"/" '{ print $2 }'
.zcompdump
.zshrc
.bashrc
.emacs
$ find ~/bin/FilesDvorak/.* -maxdepth 0 | awk -F"/" '{ print $6 }'
.bashrc
.emacs
.gdbinit
.git
I want:
A \ B:
.zcompdump
.zshrc
A Intersection B:
.bashrc
.emacs
A Union B:
.zcompdump
.zshrc
.bashrc
.emacs
.bashrc
.emacs
.gdbinit
.git
A try for the Intersection
When I save the outputs to separate lists, I cannot understand why the command does not take the common things, ie the above intersection:
find -f all_files -and -f right_files .
Questions emerged from the question:
find ~/bin/FilesDvorak/.* -maxdepth
0 -and ~/.PAST_RC_files/.*
Please, consult for recursive find
Click
here!
find ~/bin/FilesDvorak/.* -maxdepth
0 -and list
Seriously, this is what comm(1) is for. I don't think the man page could be much clearer: http://linux.die.net/man/1/comm
There are several tools that can help you find the intersection in file lists. 'find' isn't one of them. Find is for finding files that match a certain criteria on the filesystem.
Here are some ways of finding your answer.
To generate your two file lists
find . -maxdepth 1 | sort > a
(cd ~/bin/FilesDvorak/; find . -maxdepth 1 | sort > b)
Now you have two files a and b that contain directory entries without recursing into sub directories. (To remove the leading ./ you can add a "sed -e 's/^.///'" or your first awk command between the find an sort)
To find the Union
cat a b | sort -u
To find the A\B
comm -23 a b
To find the intersection
comm -12 a b
'man comm' and 'man find' for more information.

Resources