根据文件内容显示目录树

根据文件内容显示目录树
$ find ./ | tac

./dir1/file -> "abc"
./dir1
./dir2/file - > "abc"
./dir2
./dir3/file -> "xyz"
./dir3/dir3_1/file  - > "abc"
./dir3/dir3_1
./dir3

或者

$ tree

├── dir1
│   └── file -> "abc"
├── dir2
│   └── file -> "abc"
└── dir3
    ├── dir3_1
    │   └── file -> "abc"
    └── file -> "xyz"

我需要显示一个目录树(没有文件)只有那些具有包含“abc”值的“文件”文件。

我知道有一个命令tree -P 'file*'可以通过文件名过滤树,也许还有一种方法可以通过“grepping”内容来过滤树。

我也想出了做这样的事情的想法(当然它不起作用):

   $(find ./ -type f -exec grep abc {} +;) | tree -d

并以某种方式将平坦的find结果发送给tree命令。

答案1

使用tree --fromfile

在我的 Debian 10 中我有tree v1.8.0。它支持--fromfile

--fromfile
从文件而不是文件系统读取目录列表。命令行上提供的路径是要读取的文件而不是要搜索的目录。点 ( .) 目录表示tree应从标准输入读取路径。

这样我就可以使用或的tree输出来提供:findgrep -rl

grep -rl abc | tree -d --fromfile .

问题:

  • .即使根本没有匹配的文件也会被报告。

  • 如果tree读取/foo/whateverfoo/whatever则将foo被报告为子目錄.类似地,./whatever.报告为额外的级别名为.。因此,如果您使用grep -rl abc /foogrep -rl abc .find /foofind .则结果可能无法完全满足您的正式期望。

  • 带有换行符的文件名会造成混淆tree。使用grep -Zfind -print0不是一个选项,因为 没有相应的开关tree

  • 内部匹配的文件foo/bar/与内部匹配的文件一起foo/将生成与单独匹配的文件相同的输出foo/bar/。如果您看到foo/bar分支,那么您无法知道中是否有匹配的文件foo/。这是您的规范中的一个缺陷。


替代方法

下面的代码没有使用--fromfile。它修复了上面的一些问题,但速度较慢。

#!/bin/sh

tmp="$(mktemp -d)"
[ "$?" -eq 0 ] || exit 2
trap 'rm -r "$tmp"' INT TERM EXIT
dir="${2:-.}"

cd "$dir" || exit 1

find . -type f -exec grep -q "$1" {} \; -exec sh -c '
   cd "$1" || exit 1
   shift 1
   for d; do
      mkdir -p "top/$(dirname "$d")"
   done
' sh-find "$tmp" {} +

cd "$tmp" || exit 1
[ -d "top" ] || exit 0
printf "%s\n" "$dir"
tree -d --noreport "top" | tail -n +2

用法:scriptname pattern /path/to/dirscriptname pattern(则.是默认目录)。

总体流程如下:

  1. 创建一个临时目录。
  2. 对于每个匹配的文件,在临时目录中创建目录,以便相对路径对应。这样,所需的目录结构就在临时目录中建立起来了。
  3. 在临时目录中使用tree -d(调整输出,以便原始目录路径取代临时顶部节点)。
  4. 删除临时目录。

top注意,只有当至少有一个匹配项时,才会创建名为 的目录。这样我们就可以知道是否有匹配项。空输出(带有退出状态0)表示根本没有匹配项。

相关内容