$ 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
输出来提供:find
grep -rl
grep -rl abc | tree -d --fromfile .
问题:
.
即使根本没有匹配的文件也会被报告。如果
tree
读取/foo/whatever
或foo/whatever
则将foo
被报告为子目錄.
类似地,./whatever
将.
报告为额外的级别名为.
。因此,如果您使用grep -rl abc /foo
、grep -rl abc .
或find /foo
,find .
则结果可能无法完全满足您的正式期望。带有换行符的文件名会造成混淆
tree
。使用grep -Z
或find -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/dir
或scriptname pattern
(则.
是默认目录)。
总体流程如下:
- 创建一个临时目录。
- 对于每个匹配的文件,在临时目录中创建目录,以便相对路径对应。这样,所需的目录结构就在临时目录中建立起来了。
- 在临时目录中使用
tree -d
(调整输出,以便原始目录路径取代临时顶部节点)。 - 删除临时目录。
top
注意,只有当至少有一个匹配项时,才会创建名为 的目录。这样我们就可以知道是否有匹配项。空输出(带有退出状态0
)表示根本没有匹配项。