web-dev-qa-db-ja.com

ファイルの内容に基づいてdirsツリーを表示する

$ 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"

dirs tree(ファイルなし)を表示する必要があるのは、「abc」値を含む「file」ファイルを持つものだけです。

コマンドがあることを知っていますtree -P 'file*'ファイル名でツリーをフィルタリングするには、コンテンツを「grep」してツリーをフィルタリングする方法もあるかもしれません。

私はまた、このようなことをするというアイデアを思いつきました(もちろんそれは機能しません):

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

そしてどういうわけかフラットなfindの結果をtreeコマンドに送信します。

1
roman-drozd-it

tree --fromfileの使用

私のDebian10には、tree v1.8.0があります。 --fromfileをサポートします。

--fromfile
ファイルシステムではなくファイルからディレクトリリストを読み取ります。コマンドラインで提供されるパスは、検索するディレクトリではなく、読み取るファイルです。ドット(.)ディレクトリは、treeが標準入力からパスを読み取る必要があることを示します。

このようにして、treeまたはgrep -rlからの出力をfindにフィードできます。

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

問題:

  • 一致するファイルがまったくない場合でも、.が報告されます。

  • tree/foo/whateverまたはfoo/whateverを読み取る場合、foo.の-​​サブディレクトリとして報告されます。同様に、./whateverの場合:..という名前の追加レベルとして報告されます。したがって、grep -rl abc /foogrep -rl abc .find /foo、またはfind .を使用すると、結果が正式な期待を完全に満たすとは限りません。

  • 改行を含むファイル名はtreeを混乱させます。 treeに対応するスイッチがないため、grep -Zまたはfind -print0を使用することはできません。

  • 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(この場合、.がデフォルトのディレクトリです)。

一般的な手順は次のとおりです。

  1. 一時ディレクトリを作成します。
  2. 一致するファイルごとに、一時ディレクトリ内にディレクトリを作成して、相対パスが対応するようにします。このようにして、目的のディレクトリ構造が一時ディレクトリ内に構築されます。
  3. 一時ディレクトリでtree -dを使用します(出力を調整して、元のディレクトリパスが一時トップノードを置き換えるようにします)。
  4. 一時ディレクトリを削除します。

topという名前のディレクトリは、少なくとも1つ一致する場合にのみ作成されることに注意してください。このようにして、一致したかどうかを判断できます。空の出力(終了ステータス0)は、一致するものがまったくなかったことを示します。

1