ファイル名がディレクトリにない場合は、検索コマンド

ファイル名がディレクトリにない場合は、検索コマンド

特定のファイルなしでフォルダを表示する方法を知りたいです。ところで問題はファイル名は同じですが場合が違うということです。

ケース分析: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なしREADMEtoolbなしですべてのファイルを表示します。readme

答え1

find存在しないファイルを見つけるためには使用できません。ただし、それを使用してfindディレクトリを見つけて、そのディレクトリに指定されたファイル名があるかどうかをテストできます。

findディレクトリ検索を使用するとき。を使用して-type d、見つかった各ディレクトリのファイルをテストしますREADMEreadme

いくつかの最上位ディレクトリに次のディレクトリ階層があるとしますprojects

projects/
|-- toola
|   |-- doc
|   |-- readme
|   `-- src
|-- toolb
|   |-- doc
|   `-- src
|-- toolc
|   |-- README
|   |-- doc
|   `-- src
`-- toold
    |-- doc
    `-- src

ファイルを含まない直下のディレクトリを見つけるために使用されますfindprojectsREADMEreadme

$ 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

関連情報