nat*_*ath 1 ls bash wildcards shellcheck
有没有办法通过 glob 反转文件列表?
所以我会得到与以下相同的结果:
ls -r *
Run Code Online (Sandbox Code Playgroud)
我在 shell 脚本中使用它并shellcheck不断抱怨:
^--------^ SC2045:迭代 ls 输出是脆弱的。使用球体。
使用zshshell,可以使用oC(order)、OC(与^oC反向相同)和n(对于数字)glob 限定符自定义glob的排序顺序,
引用info zsh qualifier:
oC指定文件名的排序方式。如果是 C
n,则按名称排序;如果是L,则根据文件的大小(长度)对它们进行排序;如果l它们是按链接数排序的;ifa,m, orc它们分别按照上次访问、修改或inode变化的时间排序;如果d,子目录中的文件在搜索的每个级别出现在当前目录中的文件之前 - 这最好与其他条件结合使用,例如 'odon' 对同一目录中的文件的名称进行排序;如果N,则不执行排序。请注意a,m, 和c将年龄与当前时间进行比较,因此列表中的第一个名称是最年轻的文件。还要注意使用了修饰符^和-,因此“*(^-oL)”给出了所有文件的列表,这些文件按文件大小降序排序,跟在任何符号链接之后。除非oN使用,否则可能会出现多个顺序说明符来解决联系。默认排序是
n(按名称),除非使用了Yglob 限定符,在这种情况下它是N(未排序的)。
oe并且o+是特殊情况;它们每个都后跟 shell 代码,分别按照eglob 限定符和+glob 限定符分隔(见上文)。为每个匹配的文件执行代码,参数REPLY设置为条目时的文件名globsort并附加到zsh_eval_context. 代码应该REPLY以某种方式修改参数。返回时,使用参数值而不是文件名作为排序的字符串。与其他排序运算符不同,oe并且o+可以重复,但请注意,任何 glob 表达式中可能出现的任何类型的排序运算符的最大数量为 12。
所以在这里,要按逆字母顺序获取文件列表:
list=(*(NOn))
Run Code Online (Sandbox Code Playgroud)
或者
list=(*(N^on))
Run Code Online (Sandbox Code Playgroud)
(这里也使用N(for nullglob) 限定符,这样如果没有匹配的文件,列表就会变空)。
对于按修改时间倒序排序的列表(如ls -rt):
list=(*(NOm))
Run Code Online (Sandbox Code Playgroud)
使用 zsh,您还可以使用o和O参数扩展标志对数组的元素进行排序。
list=(*(N))
list_reversed=(${(Oa)list})
Run Code Online (Sandbox Code Playgroud)
也就是说,对rray 成员$list进行反向排序(因为大写O)a。
使用最新版本的bashshell 和 GNU sort,您可以获得反向排序的文件名列表:
readarray -td '' list < <(
shopt -s nullglob
set -- *
(($# == 0)) || printf '%s\0' "$@" | sort -rz)
Run Code Online (Sandbox Code Playgroud)
readarray -td '' array 将 NUL 分隔的记录列表读入数组。
随着 GNU 的实现ls,另一种方法是:
eval "list=($(ls --quoting-style=shell-always -r))"
Run Code Online (Sandbox Code Playgroud)
wherels --quoting-style=shell-always使用单引号引用文件名(并且\'在单引号之外引用单引号本身)。
这种方法也适用于yash(假设所有文件名都是语言环境中的有效文本)、ksh93、zsh和mksh,尽管对于ksh93,请确保事先将变量声明为数组(使用typeset -a list),否则如果ls没有输出,则将创建$list为复合变量而不是数组变量。
注意 ast-open 的ls实现也支持一个--quoting-style=shell-always选项,但它使用了$'...'在所有语言环境中都不能安全使用的引用形式。
POSIXly, in sh, 要反转"$@"数组,您可以执行以下操作:
eval "set -- $(awk 'BEGIN {for (i = ARGV[1]; i; i--) printf " \"${"i"}\""}' "$#")"
Run Code Online (Sandbox Code Playgroud)
这个想法是让 awk 输出类似于set -- "${3}" "${2}" "${1}"when"$@"有 3 个元素
因此,要以相反的顺序获取该文件列表:
set -- *
eval "set -- $(awk 'BEGIN {for (i = ARGV[1]; i; i--) printf " \"${"i"}\""}' "$#")"
echo file list:
printf ' - %s\n' "$@"
Run Code Online (Sandbox Code Playgroud)
当心 POSIXsh没有任何等效的nullglob选项(一项zsh发明)、zsh 的(N)glob 限定符或 ksh93 的~(N)glob 运算符。如果当前目录中没有非隐藏文件,您将得到一个只有一个*元素的列表。解决此问题的常用方法是:
set -- [*] *
case "$1$2" in
('[*]*') shift 2;;
(*) shift;;
esac
Run Code Online (Sandbox Code Playgroud)
当[*]联合*是一种方式之间的区分*是来自不匹配(其中[*]也将扩大到[*])和一个来自一个名为*字面上(其中[*]将扩大到*)。
在任何情况下,如果您要将文件名列表传递给ls它以对其进行排序,就像在ls -r *shell 将扩展传递*给它的方法中一样,您将想要使用该-d选项并标记选项的结尾与--:
ls -rd -- *
Run Code Online (Sandbox Code Playgroud)
但是,该输出仍然无法可靠地进行后处理,因为文件名由换行符分隔,并且换行符与文件名中的任何字符一样有效。