在搜索如何find
根据修改时间对找到的文件进行排序时,我发现这个答案它提供了以下咒语:
find . -type f -printf '%T@ %p\n' | sort -k 1nr | sed 's/^[^ ]* //' | head -n 10
上面的问题是我无法记住它,也无法找到一种方法将其打包为 shell 脚本,以便我可以通过自己的调用来提供它,find
我可以选择应用任何参数我想。例如,如何将上述内容打包为 shell 脚本“”的形式,showLatest
以便我可以执行以下操作?
find src -type f -iname \*.py | showLatest 10
答案1
在 zsh 中,showLatest 10
位于(om[1,10])
模式的末尾。这些都是全局限定符;om
按修改时间排序(最年轻的在前)并[1,10]
选择前 10 个匹配项。
find src -type f -iname \*.py
是print -lr src/**/(#i)*.py(D.)
(您需要setopt extended_glob
先运行,将其放入您的~/.zshrc
)。
通配标志.
仅过滤常规文件,D
包括隐藏文件和隐藏目录中的文件,就像find
版本一样。(#i)
是一个通配标志这使得模式的其余部分不区分大小写。
print -lr
print -lr --
打印其参数,每行一个(如果第一个参数可能以破折号开头,则打印该参数)。结合两者,获取最新的文件:
print -lr src/**/(#i)*.py(D.om[1,10])
在实践中您可以缩短为print -lr src/**/*.py(om[1,10])
.
在 zsh 中,您可能不需要这个,因为您可以在获得文件列表时对其进行排序,至少如果它们都来自单一模式的话。这是在 zsh 中实现的一种方法showLatest
,可以处理任意文件列表。不幸的是,om
glob 限定符只能应用于单个模式,并且单个模式只能匹配单个目录或树中的文件。绕过此问题的技巧是使用e
(或+
) glob 限定符将任意列表注入到匹配结果中。然后应用o
glob 限定符来执行排序;内置限定符不会作用于e
/+
重写的结果,但自定义限定符 (oe
或o+
) 会作用(从 zsh 5.0.5 开始)。
#!/usr/bin/env zsh
zmodload zsh/stat
files=("${(@f)$(<&0)}")
print -lr .(e\''reply=($files)'\'noe\''stat -A REPLY +mtime -- $REPLY'\')
答案2
这个脚本对我有用:
#!/bin/bash
#
while IFS= read -r line; do
find "$line" -printf '%T@ %p\n'
done | sort -k 1nr | sed 's/^[^ ]* //' | head -n 10
你可以通过它进行管道传输find
:
(0)asus-romano:~/tmp% find . -type f | ./script11.sh
./script11.sh
./script10.sh
[...]
您zsh
可以使用全局别名,这要快得多,但我认为bash
没有它们:
(0)asus-romano:~/tmp% alias -g showlast10="-printf '%T@ %p\n' | sort -k 1nr | sed 's/^[^ ]* //' | head -n 10"
(0)asus-romano:~/tmp% find . -type f showlast10
./script11.sh
./script10.sh
./Just tab.xyz
[...]
答案3
首先,当然可以编写类似的脚本showLatest
,甚至可能find
在其中使用。但这样每个文件都必须检查两次。
所以虽然这没有回答最后提出的问题,但应该解决首先描述的问题。即如何喂一个灵活的参数列表来查找。
sfind.sh:
#!/bin/bash
find "${@:1:$[$#-1]}" -printf '%T@ %p\n' | sort -k 1nr | sed 's/^[^ ]* //' | head -n ${@:$#:1}
一般的调用是sfind.sh [find-parameters] count
.对于给定的例子,它将是sfind.sh src -type f -iname \*.py 10
解释:
$@
包含传递给脚本的参数列表$#
是$@的长度${@:1:$[$#-1]}
除最后一个参数外的所有参数${@:$#:1}
最后一个参数