Sort files by depth (bash)

Is there a way in bash to sort my files from a directory in order of depth, for example, first print files in a real directory, then files in a subdirectory or subdirectories, etc., always in terms of their depth.

+4
source share
5 answers

Use the find -printf function in conjunction with sorting. See for yourself:

find . -printf "%d %p\n"|sort -n 

Creates a list sorted by depth (displaying the depth in the first column, the path to the file is the second). This prints in the current directory:

 0 . 1 ./bin 1 ./log 1 ./templates 2 ./bin/cc_env 3 ./files/test/mail.txt 

If you want to remove the first column, we can use perl:

 find . -printf "%d %p\n"|sort -n|perl -pe 's/^\d+\s//;' 

and you leave. The perl filter will remove all leading numbers. If you want to omit the directories themselves, use the "-type f" parameter:

 find . -type f -printf "%d %p\n"|sort -n|perl -pe 's/^\d+\s//;' 

Hint. Check out the find man page for more printf% d tricks.

+4
source

A likely technique would be to use find to generate file-name files, and then process the file names so that the count of slashes in the path precedes the name, and then you can sort by the number of slashes (depth), and then by name. Simple solutions assume that there are no new lines in the file names (other spaces and odd-ball characters do not matter). The interesting / difficult part is to find a clean way to count the number of slashes in a given line.

 find . -type f -print | perl -n -e '$x = $_; $x =~ tr%/%%cd; print length($x), " $_";' | sort -k 1n -k 2 | sed 's/^[0-9][0-9]* //' 

Probably a more compact way to write this Perl, but it works.

+2
source

The simplest solution:

 $ echo * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/* aa/ba/b/ca/b/c/d1 a/b/c/d2 a/b/c/d1/ea/b/c/d2/ea/b/c/d1/e/fa/b/c/d2/e/f 

Or in the column:

 $ echo * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/* |tr ' ' '\n' a a/b a/b/c a/b/c/d1 a/b/c/d2 a/b/c/d1/e a/b/c/d2/e a/b/c/d1/e/f a/b/c/d2/e/f 

The depth of the tree is hardcoded in the example, but you can write a small script and make it more flexible:

 A="*" while true do B=$(echo $A) [ "$B" = "$A" ] && break echo $B A="$A/*" done | tr ' ' '\n' 

Usage example:

 $ A="*"; while true; do B=$(echo $A); [ "$B" = "$A" ] && break; echo $B; A="$A/*"; done | tr ' ' '\n' a a/b a/b/c a/b/c/d1 a/b/c/d2 a/b/c/d1/e a/b/c/d2/e a/b/c/d1/e/f a/b/c/d2/e/f 

Examples for a tree:

 $ mkdir -pa/b/c/d{1,2}/e/f $ tree . . โ””โ”€โ”€ a โ””โ”€โ”€ b โ””โ”€โ”€ c โ”œโ”€โ”€ d1 โ”‚  โ””โ”€โ”€ e โ”‚  โ””โ”€โ”€ f โ””โ”€โ”€ d2 โ””โ”€โ”€ e โ””โ”€โ”€ f 9 directories, 0 files 

Find / in-depth solutions obviously won't work, because find will display the subtrees one by one. The -depth key indicates in which direction the subtree should be displayed. But this does not mean, of course, that the output will be sorted by depth.

 $ find . . ./a ./a/b ./a/b/c ./a/b/c/d2 ./a/b/c/d2/e ./a/b/c/d2/e/f ./a/b/c/d1 ./a/b/c/d1/e ./a/b/c/d1/e/f $ find . -depth ./a/b/c/d2/e/f ./a/b/c/d2/e ./a/b/c/d2 ./a/b/c/d1/e/f ./a/b/c/d1/e ./a/b/c/d1 ./a/b/c ./a/b ./a . 

As you can see, in both cases the answer is incorrect (with and without -find ).

+2
source

use function to recursively traverse the file system

test.sh:

 #!/bin/bash function traverse() { find $1 -mindepth 1 -maxdepth 1 ! -type d -exec echo "$2"{} \; for d in $(find $1 -mindepth 1 -maxdepth 1 -type d ! -name ".") do # if you just need files comment out next line echo "$2$d" traverse "$d" "${2} " done } traverse $1 

using:
./test.sh dir
gives the result:

 ./test.sh ./testA ./testA/dat2 ./testA/dat1 ./testA/testB ./testA/testB/dat4 ./testC ./testC/dat3 
+1
source

Use the find :

 find . -depth 

From man find :

-depth Process each contents of the directory before the directory itself.

0
source

All Articles