重命名每个组中的最新文件

fac*_*ess 1 linux bash shell

我尝试创建一个应该检测每个组的最新文件的脚本,并为其原始名称添加前缀.

ll $DIR
asset_10.0.0.1_2017.11.19 #latest
asset_10.0.0.1_2017.10.28
asset_10.0.0.2_2017.10.02 #latest
asset_10.0.0.2_2017.08.15
asset_10.1.0.1_2017.11.10 #latest
...
Run Code Online (Sandbox Code Playgroud)

2个问题:

1)如何查找每个组的最新文件?

2)如何重命名只添加前缀

我尝试了以下过程,但它在整个目录中查找最新文件,并且不保留原始名称以向其添加前缀:

find $DIR -type f ! -name 'asset*' -print | sort -n | tail -n 1 | xargs -I '{}' cp -p '{}' $DIR...
Run Code Online (Sandbox Code Playgroud)

实现这一目标的最佳方法是什么?(尽可能保持xargs)

ran*_*mir 5

选择每个组中的最新条目

您可以使用sort以仅选择每个组中的最新条目:

find . -print0 | sort -r -z | sort -t_ -k2,2 -u -z | xargs ...
Run Code Online (Sandbox Code Playgroud)

首先,按反向字典顺序对所有文件进行排序(以便最新条目首先出现在每个组中).然后,通过仅对组名进行排序(-k2,2通过下划线分割时为第二个字段-t_)并打印唯一组,我们每个组只获得第一个条目,这也是最新的.

请注意,这是因为sort使用稳定的排序算法 - 意味着订单或已排序的项目不会通过再次排序来更改.另请注意,我们无法uniq在此使用,因为我们无法为其指定自定义字段分隔符uniq(它始终是空格).

使用前缀复制

要为找到的每个文件名添加前缀,我们需要将每个路径 find生成分割为目录和文件名(basename),因为我们只需要添加prefix到filename.xargs上面的部分可能如下所示:

... | xargs -0 -I '{}' sh -c 'd="${1%/*}"; f="${1##*/}"; cp -p "$d/$f" "$d/prefix_$f"' _ '{}'
Run Code Online (Sandbox Code Playgroud)

路径拆分是通过shell参数扩展完成的,即前缀(${1##*/})和后缀(${1%/*})子串删除.


注意NUL在find(-print0而不是)中使用-terminated输出(路径-print),以及-zin sort和-0in的使用xargs.这样,完整的管道将正确处理具有"特殊"字符(如换行符和类似字符)的文件名(路径).