我尝试创建一个应该检测每个组的最新文件的脚本,并在其原始名称中添加前缀。
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
...
2个问题:
1)如何找到每组的最新文件?
2)如何重命名只添加前缀
我尝试了以下过程,但它在整个目录中查找最新文件,并且不保留原始名称以向其添加前缀:
find $DIR -type f ! -name 'asset*' -print | sort -n | tail -n 1 | xargs -I '{}' cp -p '{}' $DIR...
实现这一目标的最佳方法是什么? (如果可能,保持xargs)
答案 0 :(得分:5)
您可以使用sort
仅选择每个组中的最新条目:
find . -print0 | sort -r -z | sort -t_ -k2,2 -u -z | xargs ...
首先,按逆向字典顺序对所有文件进行排序(以便最新条目首先显示每个组)。然后,通过仅对组名进行排序(当通过-k2,2
在下划线上拆分时,该第二个字段-t_
)并打印唯一的组,我们每个组只获得第一个条目,这也是最新。
请注意,这是有效的,因为sort
使用稳定排序算法 - 这意味着订单或已排序的项目不会通过再次排序来更改。另请注意,我们无法在此使用uniq
,因为我们无法为uniq
指定自定义字段分隔符(它始终是空格)。
要为找到的每个文件名添加前缀,我们需要将每个路径 find
生成分割为目录和文件名(basename),因为我们需要添加prefix
仅限文件名。上面的xargs
部分可能如下所示:
... | xargs -0 -I '{}' sh -c 'd="${1%/*}"; f="${1##*/}"; cp -p "$d/$f" "$d/prefix_$f"' _ '{}'
路径拆分使用shell parameter expansion完成,即前缀(${1##*/}
)和后缀(${1%/*}
)substring removal。
请注意NUL
中使用find
终止的输出(路径)(-print0
而不是-print
),以及随后使用的-z
sort
中的-0
和xargs
。这样,完整的管道将使用" special"正确处理文件名(路径)。像换行符和类似的字符。
答案 1 :(得分:2)
如果您想单独使用bash执行此操作,而不是使用find
和sort
等外部工具,则需要解析"字段"在每个文件名中。
这样的事可能有用:
declare -A o=() # declare an associative array (req bash 4)
for f in asset_*; do # step through the list of files,
IFS=_ read -a a <<<"$f" # assign filename elements to an array
b="${a[0]}_${a[1]}" # define a "base" of the first two elements
if [[ "${a[2]}" > "${o[$b]}" ]]; then # compare the date with the last value
o[$b]="${a[2]}" # for this base and reassign if needed
fi
done
for i in "${!o[@]}"; do # now that we're done, step through results
printf "%s_%s\n" "$i" "${o[$i]}" # and print them.
done
这并不完全排序,它只是浏览文件列表并获取每个文件名库的最高排序值。