
特定のファイルなしでフォルダを表示する方法を知りたいです。ところで問題はファイル名は同じですが場合が違うということです。
ケース分析:toolsディレクトリの一部のサブディレクトリにはreadme
/README
ファイルが含まれており、一部のサブディレクトリには含まれていません。例えば
/toola/readme
/toolb/README
/toolc/ (does not have readme file)
このコマンドを使用して、findコマンドを使用してtoolcフォルダのみを表示したいと思います。
find . -maxdepth 2 ! -name '*readme*' -o ! -name '*README*' | awk -F "/" '{print $$2}' | uniq
しかし、これはうまくいきません。toola
なしREADME
とtoolb
なしですべてのファイルを表示します。readme
答え1
find
存在しないファイルを見つけるためには使用できません。ただし、それを使用してfind
ディレクトリを見つけて、そのディレクトリに指定されたファイル名があるかどうかをテストできます。
find
ディレクトリ検索を使用するとき。を使用して-type d
、見つかった各ディレクトリのファイルをテストしますREADME
。readme
いくつかの最上位ディレクトリに次のディレクトリ階層があるとしますprojects
。
projects/
|-- toola
| |-- doc
| |-- readme
| `-- src
|-- toolb
| |-- doc
| `-- src
|-- toolc
| |-- README
| |-- doc
| `-- src
`-- toold
|-- doc
`-- src
ファイルを含まない直下のディレクトリを見つけるために使用されますfind
。projects
README
readme
$ find projects -mindepth 1 -maxdepth 1 -type d \
! -exec test -f {}/README ';' \
! -exec test -f {}/readme ';' -print
projects/toolb
projects/toold
ここですぐ下のディレクトリを見つけて、projects
ユーティリティtest
を使用して、見つかったディレクトリのうち、これら2つのファイルのいずれも含まれていないディレクトリを確認します。
これはまさに次のとおりです。
find projects -mindepth 1 -maxdepth 1 -type d \
-exec [ ! -f {}/README ] ';' \
-exec [ ! -f {}/readme ] ';' -print
上記の別の表現は次のとおりです。
find projects -mindepth 1 -maxdepth 1 -type d -exec sh -c '
for pathname do
if [ ! -f "$pathname/README" ] &&
[ ! -f "$pathname/readme" ]; then
printf "%s\n" "$pathname"
fi
done' sh {} +
これには、実際にこれら2つのファイルをテストし、どちらも含まないディレクトリのパス名を印刷する小さなインラインシェルスクリプトがあります。このfind
ユーティリティは、インラインスクリプトが繰り返すことができるように、ディレクトリパス名の「パス名ジェネレータ」として機能します。
実際、ディレクトリ構造が次のような場合、find
まったく使用しない可能性があります。
for pathname in projects/*/; do
if [ ! -f "$pathname/README" ] &&
[ ! -f "$pathname/readme" ]; then
printf '%s\n' "$pathname"
fi
done
パターンの末尾のスラッシュを参照してくださいprojects/*/
。これは、パターンがディレクトリ(またはディレクトリへのシンボリックリンク)にのみ一致するようにすることです。
これを行うことと使用することの違いfind
は、上記のシェルループを使用すると、下の隠しディレクトリを除いてproject
ディレクトリへのシンボリックリンクが含まれることです。
いずれの場合も、ディレクトリのパス名を繰り返し、両方のファイル名が存在しないことをテストします。
唯一注目すべき点は、この-f
テストが通常のファイルへのシンボリックリンクでも機能することです。
関連:
答え2
私は明確さと優雅さに投票しますが、解決策著者: Kusalananda 私はこの種の作業がセットで作業しているように見えると付け加えました。単純なツールはfind
適していません。実際には、使用を通じて外部ツールをインポートする必要があります-exec
。
別の方法は、比較/差分ツールを使用することです。たとえば、GNUfind
およびプロセス置換をサポートするシェル (たとえば) にアクセスでき、パスにbash
改行がないとします。
comm -2 -3 <(find ./tool* -maxdepth 0 -type d | sort) \
<(find ./tool* -iname "readme" -printf "%H\n" | sort)
どこ:
comm
二つを比較するソート済み行別ファイル。このオプションを使用する-2
-3
と、2番目のファイルの結果のみを削除したり、出力から両方のファイルを削除したりできます。-printf "%H\n"
find
見つかったファイルの始点と新しい行を印刷してみましょう(-maxdepth 0
他のリストを定義するオプションと一致する必要があります)。
ツリーでテスト:
$ find ./tool* -printf "%p %y\n" | sort
./toola d
./toola/doc d
./toola/readme f
./toola/src d
./toolb d
./toolb/doc d
./toolb/src d
./toolc d
./toolc/doc d
./toolc/README f
./toolc/src d
./toold d
./toold/doc d
./toold/doc/readme f
./toold/src d
上記のコマンドは以下を提供します。
./toolb
答え3
そしてzsh
:
set -o extendedglob # for (#i) for case insensitive matching
all_projects=(projects/*(-/))
typeset -aU projects_with_readme # -U for unique
projects_with_readme=(projects/*/(#i)readme(:h))
projects_without_readme=(${all_projects:|projects_with_readme})
echo Projects with READMEs:
printf ' - %s\n' $projects_with_readme
echo Projects without READMEs:
printf ' - %s\n' $projects_without_readme
(#i)readme
次のように変更して、(#i)*readme*
名前付きREADME.txt
ファイルのみを考慮する000README
か、次に(:h)
変更できます。(-.:h)
閲覧ファイルファイルは定期的なシンボリックリンクを確認した後(ディレクトリ、壊れたリンク、その他の特殊タイプのファイルを除く)
答え4
私は以下を使用します:
find -type d -maxdepth 2 -not -name '*readme*' | awk -F "/" '{print $$2}' | uniq