Here is a sample directory tree as it would appear if it were sorted in character code order (i.e., directories are not listed first):
${PREFIX}/ .bashrc .include.sh.d/ common.sh applications.txt docs/ contacts.docx parts/ docs-/ docs./ timestamp.txt Now, suppose that we want to use find "${PREFIX} -mindepth 1 plus some additional arguments and CLI tools:
.include.sh.d/ .include.sh.d/common.sh docs/ docs/parts/ docs/contacts.docx docs-/ docs./ applications.txt timestamp.txt Note four things about the text in the second codeblock:
- Paths which are directories are appended with a
/. - The children of a directory are first sorted by type—directories come first, followed by files—and then by character code; when this is applied as a rule, it places
dir/,dir/-file,dir-/, anddir-/filein exactly that order. This is the way files/directories are sorted bytree --dirsfist "${PREFIX}"(the rest of formatting is still different). - Corollary to #2: The
/behaves as a field separator, leading todocs/coming beforedocs-/despite-coming before/in the ASCII character table. - Corollary to #2: Any given directory is contiguous with all of its descendants.
With find "${PREFIX} -not -path "${PREFIX}" -printf "%P\n" | sort -t "/", the result is this:
.include.sh.d .include.sh.d/common.sh applications.txt docs docs- docs. docs/contacts.docx docs/parts timestamp.txt The problems with the are as follows:
- Directories are not appended with
/, thereby breaking #1. - There are files coming before directories that they share their parent directory with, thereby directly breaking #2.
docs/{contacts.txt,parts}do not come immediately afterdocs, but ratherdocs{-,.}are sandwiched between the two groups, thereby breaking #4 and, both directly and by extension, #2.
With `find "${PREFIX} -not -path "${PREFIX}" ( -type f -printf "%P\n" , -type d -printf "%P/\n" ) | sort -t "/", we instead get:
.include.sh.d .include.sh.d/common.sh applications.txt docs-/ docs./ docs/ docs/contacts.docx docs/parts/ timestamp.txt In this case, directories are appended with / and directories are only ever immediately followed by all of their descendents, which satisfies #1 and #3, but these problems remain:
- There are one more files coming before one or more sibling directories of theirs, thereby directly breaking #2.
docs/is preceded bydocs-/anddocs./, thereby breaking #4 and, both directly and by extension, #2.
Is there any way that I can satisfy all 4 requirements while still using find for this task? If so, how? If not, what sequence of commands is at least as fast using find and sort? I'd prefer if find "${PREFIX}" -mindepth 1 \( -type f -printf "%P\n", -type l -xtype f -printf "%P\n", -type d -printf "%P/\n", -type l -xtype d -printf "%P/\n", -xtype l -printf "%P\n" \) is the first command because I want to treat symlinks to directories as directories for the purposes of rule #2.
Update: I've come up with a sequence of commands that for pipung find's output into that groups directories before the files that they are siblings of: sed -r -e 's:[^/]+/:0&:g;s:[^/*]+$:1&:g'| sort -t "/" | sed 's/^[01]//g;s/\/[01]/\//g'.