7

我有一个看起来像这样的文件结构

./501.res/1.bin
./503.res/1.bin
./503.res/2.bin
./504.res/1.bin

我想.bin在每个目录中找到文件名最大的文件的文件路径。所以我正在寻找的输出将是

./501.res/1.bin
./503.res/2.bin
./504.res/1.bin

一个文件可以有的最大数字是 9。

问题

我如何在 BASH 中做到这一点?

我已经到了find .|grep bin|sort

4

6 回答 6

3

Glob 保证按词汇顺序扩展。

for dir in ./*/
do
    files=($dir/*)           # create an array
    echo "${files[@]: -1}"   # access its last member
done
于 2012-06-22T14:42:59.997 回答
2

测试:

find . -type d -name '*.res' | while read dir; do
    find "$dir" -maxdepth 1 | sort -n | tail -n 1
done
于 2012-06-22T14:29:56.517 回答
2

怎么用awk?你可以很简单地得到第一次出现:

[ghoti@pc ~]$ cat data1
./501.res/1.bin
./503.res/1.bin
./503.res/2.bin
./504.res/1.bin
[ghoti@pc ~]$ awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' data1
./501.res/1.bin
./503.res/1.bin
./504.res/1.bin
[ghoti@pc ~]$ 

要获得最后一次出现,您可以通过几种管道:

[ghoti@pc ~]$ sort -r data1 | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort
./501.res/1.bin
./503.res/2.bin
./504.res/1.bin
[ghoti@pc ~]$ 

鉴于您正在使用“find”和“grep”,您可能可以这样做:

find . -name \*.bin -type f -print | sort -r | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort

这是如何运作的?

find命令有许多有用的选项,包括通过 glob 选择文件、选择文件类型等的能力。它的输出你已经知道,它成为sort -r.

首先,我们对输入数据进行反向排序(sort -r)。这确保了在任何目录中,编号最高的文件将首先出现。该结果被输入 awk。FS 是字段分隔符,它$2包含“/501”、“/502”等内容。Awk 脚本具有condition {action}对每一行输入进行评估的部分。如果缺少某个条件,则该操作将在每一行上运行。如果条件为“1”且没有操作,则打印该行。所以这个脚本分解如下:

  • a[$2] {next}- 如果存在下标$2(即“/501”)的数组a,则直接跳到下一行。否则...
  • {a[$2]=1}- 将数组下标 $2 设置为 1,以便将来第一个条件评估为真,然后...
  • 1- 打印该行。

此 awk 脚本的输出将是您想要的数据,但顺序相反。最后sort将事情按您期望的顺序放回原处。

现在......这是很多管道,当您要求它同时处理数百万行输入时,排序可能会有点资源消耗。这个解决方案对于少量文件来说已经足够了,但是如果你要处理大量的输入,请告诉我们,我可以提出一个一体化的 awk 解决方案(这将需要超过 60 秒来写)。

更新

根据 Dennis 的明智建议,我上面包含的 awk 脚本可以通过将其从

BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1

BEGIN{FS="."} $2 in a {next} {a[$2]} 1

虽然这在功能上是相同的,但优点是您只需定义数组成员而不是为它们分配值,这可能会节省内存或 cpu,具体取决于您的 awk 实现。无论如何,它更干净。

于 2012-06-22T14:30:34.460 回答
1

我想出了这样的东西:

for dir in $(find . -mindepth 1 -type d | sort); do
   file=$(ls "$dir" | sort | tail -n 1);
   [ -n "$file" ] && (echo "$dir/$file");
done

也许它可以更简单

于 2012-06-22T14:29:29.193 回答
0

如果从 find 中调用 shell 是一个选项,试试这个

  find * -type d -exec sh -c "echo -n './'; ls -1 {}/*.bin | sort -n -r | head -n 1" \;
于 2012-06-22T14:38:24.023 回答
0

这是一个班轮

find . -mindepth 1 -type d | sort | sed -e "s/.*/ls & | sort | tail -n 1 | xargs -I{} echo &\/{}/" | bash
于 2012-06-22T14:45:44.977 回答