hek2mgl's answer explains the problem well and his solution works well; this answer looks at performance.
The accepted answer is a tad slow, because it creates a bash
process for every input line.
While xargs
is generally preferable to and faster than a shell-code loop, in this particular case the roles are reversed, because shell functionality is needed in each iteration.
The following alternative solution uses a while
loop to process the input lines, and, on my machine, is about twice as fast as the xargs
solution.
find . -printf "%P\n" | sort | while IFS= read -r f; do echo "$(uuid) $f"; done
If you're concerned about filenames with embedded newlines (very rare) and use GNU utilities, you could use NUL bytes as separators:
find . -printf "%P\0" | sort -z | while IFS= read -d '' -r f; do echo "$(uuid) $f"; done
Update: The fastest approach is to not use a shell loop at all, as evidenced by ᴳᵁᴵᴰᴼ's clever answer.
See below for a portable version of his answer.
Compatibility note:
The OP's find
command implies the use of GNU find
(Linux), and uses features (-printf
) that may not work on other platforms.
Here's a portable version of ᴳᵁᴵᴰᴼ's answer that uses only POSIX-compliant features of find
(and awk
).
Note, however, that uuid
is not a POSIX utility; since Linux and BSD-like systems (including OSX) have a uuidgen
utility, the command uses that instead:
find . -exec printf '%s\t' {} \; -exec uuidgen \; |
awk -F '\t' '{ sub(/.+\//,"", $1); print $2, $1 }' | sort -k2