如何按修改时间排序和过滤图像并在 FreeBSD 上的 nsxiv 中查看它们

如何按修改时间排序和过滤图像并在 FreeBSD 上的 nsxiv 中查看它们

我在用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”前缀:gnulsgfindgxargsgmake和。gsedgawk

如果您讨厌给您心爱的 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)$'
  • 在所有者或组名称中存在空格字符的特殊情况下,可能需要将选项添加-nls,以便ls输出用户 ID 和组 ID 而不是名称。

相关内容