nat*_*ath 1 ls bash wildcards shellcheck
有没有办法通过 glob 反转文件列表?
所以我会得到与以下相同的结果:
ls -r *
Run Code Online (Sandbox Code Playgroud)
我在 shell 脚本中使用它并shellcheck
不断抱怨:
^--------^ SC2045:迭代 ls 输出是脆弱的。使用球体。
使用zsh
shell,可以使用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
(按名称),除非使用了Y
glob 限定符,在这种情况下它是N
(未排序的)。
oe
并且o+
是特殊情况;它们每个都后跟 shell 代码,分别按照e
glob 限定符和+
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
。
使用最新版本的bash
shell 和 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)
但是,该输出仍然无法可靠地进行后处理,因为文件名由换行符分隔,并且换行符与文件名中的任何字符一样有效。