我有一个包含许多文件的目录。
例子:
aaa.txt
bbb.txt
ccc.txt
ddd.txt
给定一个任意字符串(不一定是其中一个文件的名称),我想找到在该字符串之前排序的所有文件(按正常字母顺序排序)。
示例:给出ccc.txt
我想要查找bbb.txt
和aaa.txt
。
文件名仅包含普通 ASCII 字符。LC_ALL=C
可以假设。没有隐藏文件(以 开头.
)。
一个潜在的解决方案可能是这样的(带有一个弥补的测试):
$ find -isnamelessthan ccc.txt
aaa.txt
bbb.txt
如何才能做到这一点?
和
zsh
:在哪里:
print -rC1 --
print
s 其参数r
aw 和 on1
C
olumn**/
匹配任何级别的子目录(包括 0)以进行递归搜索,就像find
这样。(...)
是进一步限定匹配的全局限定符:N
print
: nullglob 以便在没有匹配项时不报告错误(并且不打印任何内容):D
: dotglob 与 with 类似find
,不排除隐藏文件e['code']
:运行代码以查看是否应选择该文件。这里的代码是对(正在考虑的文件路径)的 ail (基本名称)与[[ $REPLY:t < ccc.txt ]]
进行词法比较(使用memcmp()
,而不是区域设置感知strcoll()
函数)。t
$REPLY
ccc.txt
在 GNU 系统上,您可以使用以下命令(在任何 shell 中)执行类似的操作:
在哪里:
-mindepth 1
,排除起始文件 (.
)。您也可以使用标准! -name .
,尽管它不能扩展到其他起始文件²。-printf '%P\0'
打印文件相对于起始文件的路径,例如dir/aaa.txt
for./dir/a.txt
,由 NUL 字节分隔(文件路径中不能出现的唯一字节值)。sort -z
按照/globsstrcoll()
的方式对列表进行排序。ls
LC_ALL=C
将(如sstrcoll()
使用的)转换为(在基于 ASCII 的系统上)awk
<
memcmp()
-v RS='\0'
将输入R
ecordS
分隔符设置为 NUL 字节(ORS
保留换行符的默认值)-F/
,缩写,将字段分离器-v FS=/
设置为。F
S
/
$NF < "ccc.txt"
:将最后一个字段与"ccc.txt"
词法进行比较,如果为真,则运行默认操作({print}
的缩写{print $0}
)来打印记录。对于
-isnamelessthan
find
谓词,您可以执行以下操作(在 zsh 中):用作:
(效率不高,因为它运行一个实例来
zsh
检查每个文件)。¹ 虽然 glob 本身是根据语言环境进行排序的,所以使用
strcoll()
² 虽然您不能
find /path/to/dir ! -name dir
这样做,因为这会排除内部也调用的文件dir
,但您可以这样做find /path/to/dir/. ! -name .
。假设您的文件名不包含换行符,则使用任何 awk:
我会创建一个像这样的简单函数:
第一个参数是输入字符串,第二个参数是目标目录。
请注意,如果您的文件名称中包含换行符,这将会中断。如果您使用 GNU ls,那么您可以添加标志
-b
来转义某些字符,例如换行符。sed 正则表达式转义来自:https://stackoverflow.com/a/29613573
gawk
Stéphane Chazelas 和 Ed Morton 使用和发布了很好的答案awk
,似乎用一行就优雅地解决了问题。然而,未来的程序员必须知道
awk
如何详细理解这些解决方案。因此,我认为在我的情况下最好使用简单的 for 循环。我会接受 Stéphane 的答案,因为它有最好的解释,但也在这里留下我自己的解决方案。
您不应该解析 的输出
ls
。我假设输入已排序并且每行有一个文件。你可以使用
sed
: