![按日期对 bash 中的文件数组列表进行排序并绕过参数限制](https://linux22.com/image/217224/%E6%8C%89%E6%97%A5%E6%9C%9F%E5%AF%B9%20bash%20%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E6%95%B0%E7%BB%84%E5%88%97%E8%A1%A8%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%E5%B9%B6%E7%BB%95%E8%BF%87%E5%8F%82%E6%95%B0%E9%99%90%E5%88%B6.png)
因此,我在 bash shell 中有一个文件数组列表,我想按修改日期对数组中的所有文件进行排序,从最旧的文件开始是数组中的第一个文件。但是,我不想对原始数组进行排序和修改,而是希望将排序结果放在不同的数组中。我看见这个线程我在其中尝试了以下命令,尽管我修改了它,因为数组是变量而不是文件。
new_array=( $(ls -t $(printf '%s\n' "${array_list[@]}")) )
但是,数组太大,以至于 ls 报告参数列表“太长”
是否有另一种方法可以按修改日期对主数组进行排序,从最旧的文件开始,并将结果保存到不同的数组?
答案1
使用较新版本的 GNUls
和bash
,您可以执行以下操作:
readarray -td '' new_array < <(
ls --zero -dt -- "${array_list[@]}")
但这并没有绕过execve()
参数+环境长度的限制,因为我们是ls
使用该参数列表执行。您可以将该列表传递给printf
不执行的函数或内置函数,execve()
以将其输入到可以从 stdin 读取列表而不是作为参数的命令中。
对于最新版本的 GNU find
(以及 GNUsort
和cut
):
print0() { [ "$#" -eq 0 ] || printf '%s\0' "$@"; }
readarray -td '' new_array < <(
print0 "${array_list[@]}" |
find -files0-from - -prune -printf '%T@\t%p\0' |
sort -rzn |
cut -zf2 -)
或者使用 GNUstat
并假设没有任何数组元素-
:
print0() { [ "$#" -eq 0 ] || printf '%s\0' "$@"; }
readarray -td '' new_array < <(
print0 "${array_list[@]}" |
xargs -r0 stat --printf='%.Y\t%n\0' --
sort -rzn |
cut -zf2 -)
zsh
有一个stat
内置的(早于 GNU 的)。因此,您可以直接在那里执行以下操作:
zmodload zsh/stat
typeset -A mtime
stat -nLA mtime -F %s%9. +mtime -- $array_list
new_array=( /(Ne['reply=($array_list)']nOe['REPLY=$mtime[$REPLY]']) )
这里构建一个关联数组以将文件映射到其生成时间,并使用glob 限定符 with (对于数字)对$mtime
A
列表进行排序。Oe
n