我在用nsxiv在 FreeBSD 上查看 JPEG 和 PNG 图像。但是,我无法找到一种按修改时间对图像进行排序和过滤的方法,以便在 FreeBSD 上的 nsxiv 中查看它们。在使用 GNU coreutils 和 GNU findutils 的 Linux 上,我可以使用以下命令查看 2023 年 10 月 1 日之后修改的图像,按修改时间排序。
find . -maxdepth 1 -type f \
\( -iregex '.+\.jpe?g$' -o -iregex '.+\.png$' \) \
-newermt 2023-10-01 \
-exec ls -t --zero -- {} + | \
nsxiv -0 -
我无法在 FreeBSD 上找到能够处理包含空格、换行符和其他异常字符的文件名的等效命令。问题是 FreeBSD 的ls
没有--zero
选项输出 NUL 分隔的文件名以通过管道传输到nsxiv
.另一个问题是 FreeBSD 的find
没有-printf0
可用于获取可传递给sort -z
.如何按修改时间对图像进行排序和过滤并在 FreeBSD 上的 nsxiv 中查看它们?
我在 Linux 和 FreeBSD 上使用/bin/sh
(dash) /bin/sh
。
答案1
如果能够在普通的 FreeBSD 系统上运行对您来说很重要,那么还有 find/xargs/cut/stat 的另一个答案。如果您能够安装其他实用程序,那么使用 zsh 也有更清晰的答案。
但如果你习惯了 GNUism 和 Linux,那么如果你安装了 GNU,那么在 FreeBSD 上过上舒适的生活是很容易的查找工具。
pkg install findutils
同样,人们也被 BSD ls、grep、make、sed 和 awk 所困扰。但他们的 GNU 对应版本也很容易获得格努尔斯,格努格雷普,gmake,格萨德和呆呆地。你要去吗全部投入然后得到核心工具
它们都可以与您系统上的 BSD 版本共存。然后,您通常会在命令前加上 GNU 版本的“g”前缀:gnuls
、gfind
、gxargs
、gmake
和。gsed
gawk
如果您讨厌给您心爱的 gnu 变体添加前缀,请参阅“如何使 GNU grep 成为 FreeBSD 中的默认值?”
如果您习惯了 BSD 变体,那么它们也可以在 Linux 上使用。看bsdutils
答案2
您必须正确地通过 xargs 才能完成排序;所以,像
find . -maxdepth 1 -type f \
\( -iregex '.+\.jpe?g$' -o -iregex '.+\.png$' \) \
-newermt 2023-10-01 \
-print0 \
\|
xargs -0 \
stat -n -f '%Y %N\0' \
\|
sort -z \
\|
cut -z -d ' ' -f2- \
\|
nsxiv -0 -
我们使用“装饰 - 排序 - 取消装饰”技巧,您通常会在带有元组的语言中找到这种技巧。在这里,我们需要用空格将排序键(统计中自纪元以来的秒数%Y
)与值(文件名)分开。然后又cut
回来了。有点尴尬!
答案3
你可以这样做:
zsh +o caseglob -c '
autoload after
print -rN -- *.(jp(e|)g|png)(.e[after 2023-10-01]om)' | nsxiv -0 -
对于便携性+可靠性,perl
可能是您最好的选择:
perl -MTime::HiRes=lstat -MPOSIX -MFile::Glob=:nocase -e '
$start = mktime(0,0,0, 1,10-1,2023-1900); # 2023-10-01
for (<*.{jpg,jpeg,png}>) {
push @files, [$_, $s[9]] if @s = lstat and -f _ and $s[9] >= $start;
}
print "$_->[0]\0" for sort {$b->[1] <=> $a->[1]} @files
' | nsxiv -0 -
请注意,您的-exec ls -t --zero -- {} +
如果文件列表足够大,find
需要调用ls
多次,则无法正常按修改时间对文件进行排序。
答案4
我找到了一个适用于 FreeBSD 的解决方案/bin/sh
。我在 FreeBSD 13.2 中尝试过。它似乎可以正确处理包含反斜杠和空格(空格、制表符和换行符)的文件名,包括前导和尾随空格。
find . -maxdepth 1 -type f \
\( -iregex '.\{1,\}\.jpe\{0,1\}g$' -o -iregex '.\{1,\}\.png$' \) \
-newermt 2023-10-01 \
-exec ls -l -B -D%s {} + \
| cut -w -f6- | sort -r | cut -f2- \
| while read -r line; do
printf '%b\0' "$line"
done \
| nsxiv -0 -
怎么运行的:
ls -l -B -D%s
-B
以八进制表示法显示不可打印的字符。这对于处理包含换行符和制表符的文件名非常重要。-D%s
格式文件修改时间(自纪元以来的秒数)。这对于按修改时间排序很有用。
cut -w -f6-
:从输出中删除ls -l ...
除包含文件修改时间和文件名的列之外的所有列。-w
必须将连续的空格算作一个分隔符。sort -r
:按照修改时间从最近修改到最早修改的顺序对文件进行排序。cut -f2-
:删除文件修改时间列,仅保留(换行符分隔的)文件名。- 最后一部分:逐个读取换行符分隔的文件名,并使用 的
printf
格式%b
字符串将文件名中的八进制表示法转换回实际字符(即包括换行符和制表符)。使用 NULL 字符 (\0
) 分隔文件名,将 NULL 分隔的文件名通过管道传输到nsxiv -0 -
.
补充笔记:
cut -w -f6- | sort -r | cut -f2-
ls
不能用的选项代替-t
。正如用户“Stéphane Chazelas”在此网页的另一个答案中写道:find ... -exec ls -t ... -- {} +
如果文件列表足够大,find
需要调用ls
多次,[ ] 将无法正常按修改时间对文件进行排序。find ... \( -iregex '.\{1,\}\.jpe\{0,1\}g$' -o -iregex '.\{1,\}\.png$' \)
可以通过使用扩展正则表达式来简化。例如find -E ... -iregex '.+\.(jpe?g|png)$'
。- 在所有者或组名称中存在空格字符的特殊情况下,可能需要将选项添加
-n
到ls
,以便ls
输出用户 ID 和组 ID 而不是名称。