Selecting the latest entry in each group
You can use sort
to select only the latest entry in each group:
find . -print0 | sort -r -z | sort -t_ -k2,2 -u -z | xargs ...
First, sort all files in reversed lexicographical order (so that the latest entry appears first for each group). Then, by sorting on group name only (that's second field -k2,2
when split on underscores via -t_
) and printing unique groups we get only the first entry per each group, which is also the latest.
Note that this works because sort
uses a stable sorting algorithm - meaning the order or already sorted items will not be altered by sorting them again. Also note we can't use uniq
here because we can't specify a custom field delimiter for uniq
(it's always whitespace).
Copying with prefix
To add prefix to each filename found, we need to split each path find
produces to a directory and a filename (basename), because we need to add prefix
to filename only. The xargs
part above could look like:
... | xargs -0 -I '{}' sh -c 'd="${1%/*}"; f="${1##*/}"; cp -p "$d/$f" "$d/prefix_$f"' _ '{}'
Path splitting is done with shell parameter expansion, namely prefix (${1##*/}
) and suffix (${1%/*}
) substring removal.
Note the use of NUL
-terminated output (paths) in find
(-print0
instead of -print
), and the accompanying use of -z
in sort
and -0
in xargs
. That way the complete pipeline will properly handle filenames (paths) with "special" characters like newlines and similar.