How do I recursively list all directories at a location, breadth-first?
The find command supports -printf option which recognizes a lot of placeholders.
One such placeholder is %d which renders the depth of given path, relative to where find started.
Therefore you can use following simple one-liner:
find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-
It is quite straightforward, and does not depend on heavy tooling like perl .
- it internally generates list of files, each rendered as a two-field line
- the first field contains the depth, which is used for (reverse) numerical sorting, and then cut away
- resulting is simple file listing, one file per line, in the deepest-first order
If you want to do it using standard tools, the following pipeline should work:
find . -type d | perl -lne 'print tr:/. " $_"' | sort -n | cut -d' ' -f2
- find and print all the directories here in depth first order
- count the number of slashes in each directory and prepend it to the path
- sort by depth (i.e., number of slashes)
- extract just the path.
To limit the depth found, add the -maxdepth argument to the find command.
If you want the directories listed in the same order that find output them, use «sort -n -s» instead of «sort -n»; the «-s» flag stabilizes the sort (i.e., preserves input order among items that compare equally).
Add «2>/dev/null» to the find command, i.e., find . -type d 2>/dev/null Will ensure that find error don’t screw up the results.
Does not work if dirnames have spaces. For instance, if a dir is «/data/Mundial/Trinidad\ y\ Tobago/» you will have just «/data/arbol/Mundial/Trinidad».
Thank you, this is the best one liner for sorting paths breadth-first that I’ve found (ignoring issues like spaces in pathnames). If you need to sort depth-first, see this explanation for a sort callback with strcmp() on each path element, returning length1 — length2 if components all match (equivalent to treating nonexistent components as empty strings) stackoverflow.com/a/4820233/539149
You can use find command, find /path/to/dir -type d So below example list of directories in current directory :
My feeling is that this is a better solution than previously mentioned ones. It involves grep and such and a loop, but I find it works very well, specifically for cases where you want things line buffered and not the full find buffered.
It is more resource intensive because of:
- Lots of forking
- Lots of finds
- Each directory before the current depth is hit by find as many times as there is total depth to the file structure (this shouldn’t be a problem if you have practically any amount of ram. )
- It uses bash and basic gnu tools
- It can be broken whenever you want (like you see what you were looking for fly by)
- It works per line and not per find, so subsequent commands don’t have to wait for a find and a sort
- It works based on the actual file system separation, so if you have a directory with a slash in it, it won’t be listed deeper than it is; if you have a different path separator configured, you still are fine.
#!/bin/bash depth=0 while find -mindepth $depth -maxdepth $depth | grep '.' do depth=$((depth + 1)) done
You can also fit it onto one line fairly(?) easily:
depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done
But I prefer small scripts over typing.
I don’t think you could do it using built-in utilities, since when traversing a directory hierarchy you almost always want a depth-first search, either top-down or bottom-up. Here’s a Python script that will give you a breadth-first search:
import os, sys rootdir = sys.argv[1] queue = [rootdir] while queue: file = queue.pop(0) print(file) if os.path.isdir(file): queue.extend(os.path.join(file,x) for x in os.listdir(file))
- Using os.path -module instead of os.stat -function and stat -module.
- Using list.pop and list.extend instead of del and += operators.
I tried to find a way to do this with find but it doesn’t appear to have anything like a -breadth option. Short of writing a patch for it, try the following shell incantation (for bash):
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; while test -n "$LIST"; do for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done
I sort of stumbled upon this accidentally so I don’t know if it works in general (I was testing it only on the specific directory structure you were asking about)
If you want to limit the depth, put a counter variable in the outer loop, like so (I’m also adding comments to this one):
# initialize the list of subdirectories being processed LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; # initialize the depth counter to 0 let i=0; # as long as there are more subdirectories to process and we haven't hit the max depth while test "$i" -lt 2 -a -n "$LIST"; do # increment the depth counter let i++; # for each subdirectory in the current list for F in $LIST; do # print it echo $F; # double-check that it is indeed a directory, and if so # append its contents to the list for the next level test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; # set the current list equal to the next level's list LIST=$NLIST; # clear the next level's list NLIST=""; done
(replace the 2 in -lt 2 with the depth)
Basically this implements the standard breadth-first search algorithm using $LIST and $NLIST as a queue of directory names. Here’s the latter approach as a one-liner for easy copy-and-paste:
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; let i=0; while test "$i" -lt 2 -a -n "$LIST"; do let i++; for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done
Ls Command in Linux (List Files and Directories)
ls is one of the basic commands that any Linux user should know.
The ls command lists files and directories within the file system, and shows detailed information about them. It is a part of the GNU core utilities package which is installed on all Linux distributions.
This article will show you how to use the ls command through practical examples and detailed explanations of the most common ls options.
How to Use the ls Command #
The syntax for the ls command is as follows:
When used with no options and arguments, ls displays a list of the names of all files in the current working directory :
The files are listed in alphabetical order in as many columns as can fit across your terminal:
cache db empty games lib local lock log mail opt run spool tmp
To list files in a specific directory, pass the directory path as an argument to the ls command. For example, to list the contents of the /etc directory, you would type:
You can also pass multiple directories and files separated by space:
If the user you are logged in with doesn’t have read permissions to the directory, you will get a message saying that ls can’t open the directory:
ls: cannot open directory '/root': Permission denied
The ls command has a number of options. In the sections below, we will explore the most commonly used options.
Long Listing Format #
The default output of the ls command shows only the names of the files and directories, which is not very informative.
The -l ( lowercase L) option tells ls to print files in a long listing format.
When the long listing format is used, you can see the following file information:
- The file type.
- The file permissions.
- Number of hard links to the file.
- File owner.
- File group.
- File size.
- Date and Time.
- File name.
-rw-r--r-- 1 root root 337 Oct 4 11:31 /etc/hosts
Let’s explain the most important columns of the output.
The first character shows the file type. In this example, the first character is — , which indicates a regular file. Values for other file types are as follows:
- — — Regular file.
- b — Block special file.
- c — Character special file.
- d — Directory.
- l — Symbolic link.
- n — Network file.
- p — FIFO.
- s — Socket.
The next nine characters are showing the file permissions. The first three characters are for the user, the next three are for the group, and the last three are for others. You can change the file permissions with the chmod command. The permission character can take the following value:
- r — Permission to read the file.
- w — Permission to write to the file.
- x — Permission to execute the file.
- s — setgid bit.
- t — sticky bit.
In our example, rw-r—r— means that the user can read and write the file, and the group and others can only read the file. The number 1 after the permission characters is the number of hard links to this file.
The next two fields root root are showing the file owner and the group, followed by the size of the file ( 337 ), shown in bytes. Use the -h option if you want to print sizes in a human-readable format. You can change the file owner using the chown command.
Oct 4 11:31 is the last file modification date and time.
The last column is the name of the file.
Show Hidden Files #
By default, the ls command will not show hidden files. In Linux, a hidden file is any file that begins with a dot ( . ).
To display all files including the hidden files use the -a option:
drwxr-x--- 10 linuxize linuxize 4096 Feb 12 16:28 . drwxr-xr-x 18 linuxize linuxize 4096 Dec 26 09:21 .. -rw------- 1 linuxize linuxize 1630 Nov 18 2017 .bash_history drwxr-xr-x 2 linuxize linuxize 4096 Jul 20 2018 bin drwxr-xr-x 2 linuxize linuxize 4096 Jul 20 2018 Desktop drwxr-xr-x 4 linuxize linuxize 4096 Dec 12 2017 .npm drwx------ 2 linuxize linuxize 4096 Mar 4 2018 .ssh
Sorting the Output #
As we already mentioned, by default, the ls command is listing the files in alphabetical order.
The —sort option allows you to sort the output by extension, size, time and version:
- —sort=extension (or -X ) — sort alphabetically by extension.
- —sort=size (or -S ) — sort by file size.
- —sort=time ( or -t ) — sort by modification time.
- —sort=version (or -v ) — Natural sort of version numbers.
If you want to get the results in the reverse sort order, use the -r option.
For example, to sort the files in the /var directory by modification time in the reverse sort order you would use:
It’s worth mentioning that the ls command does not show the total space occupied by the directory contents. To get the size of a directory , use the du command.
List Subdirectories Recursively #
The -R option tells the ls command to display the contents of the subdirectories recursively:
Conclusion #
The ls command lists information about files and directories.
For more information about ls visit the GNU Coreutils page or type man ls in your terminal.
If you have any questions or feedback, feel free to leave a comment.