一部のファイルは存在しますが、他のファイルは存在しないディレクトリを見つける方法

一部のファイルは存在しますが、他のファイルは存在しないディレクトリを見つける方法

レポートディレクトリが多く、report.mdディレクトリにレポートが含まれているファイルは常に存在しますが、report.pdf完了したレポートにのみあるとします。存在を探したいのですがreport.md何もありませんreport.pdf

reports_dir
|
+-- project_xyz
|   +-- report.md
|   +-- image.png
|
+-- bugs
|   +-- report.md
|   +-- report.pdf
|   +-- Makefile
|
+-- homework
    +-- report.pdf
    +-- test.md

この機能をsearch "reports_dir" --include "report.md" --exclude "report.pdf"次のように使用する/project_xyzと、/bugs/homework

sh/でこれらの検索を実行する最速の方法は何ですかbash? (シングルライン優先順位)

答え1

for f in "$1"/*/"$2"; do dir=$(dirname -- "$f"); [ -f "$dir/$3" ] || printf '%s\n' "$dir"; done

スクリプトの最初のパラメータは親ディレクトリsearch、2番目のパラメータはインクルードディレクトリ、3番目のパラメータは除外ディレクトリです。

sh search "reports_dir" "report.md" "report.pdf"
  • "$1"/*/"$2"report.md例では、ファイルパスのみを取得します。

  • dir=$(dirname -- "$f")このファイルのディレクトリパスを取得します(改行文字で終わらないと仮定)。

  • [ -f "$dir/$3" ]ディレクトリ()の3番目のパラメータにファイルが存在するかどうかをテストしますreport.pdf定期的なタイプ(ディレクトリ、fifo、デバイス...いいえ)。

  • || printf '%s\n' "$dir"存在しない場合(または存在しない場合)定期的なファイル)、ディレクトリ名を印刷します。

答え2

そしてzsh

print -rC1 -- **/report.md(DN^e['[[ -e $REPLY:r.pdf ]]']:h)

コード評価がtrue(ファイルのoot名を含む場合)を返さないot(隠し)ファイルを含む、すべてのレベルのサブディレクトリ()の下にあるファイルのolumn ead(dirname)print rについてawを確認します。 )。1 Chreport.md**/De[[ -e $REPLY:r.pdf ]]^$REPLY:rr$REPLY

組み込みの引数とBourne様シェル(GNUを含む)の実装を許可すると、find次のことができます。find{}-execbash

find . -type d -exec test -e '{}/report.md' \; \
             ! -exec test -e '{}/report.pdf' \; -print

testただし、これはディレクトリごとに最大2つのコマンドを実行することを意味します。

内蔵機能を使用すると、次の方法でこれらの問題を回避できますboshfind

find . -type d -call '
  [ -e "$1/report.md" ] && [ ! -e "$1/report.pdf" ]' {} \; -print

今回は-callシェルがコードを直接解釈して組み込まれた[

POSIX的に:

find . -type d -exec sh -c '
  for d do
    [ ! -e "$d/report.md" ] || [ -e "$d/report.pdf" ] || printf "%s\n" "$d"
  done' sh {} +

組み込みの実装sh(最近のほとんど)では、見つかったディレクトリのリストを処理するためにできるだけ少ない回数で呼び出す必要があるため、比較的効率的です。[printfshfind

答え3

短いbash 1行ステートメントを使用して、PDFが存在するかどうかをテストできます(-execフィルタも可能)。

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -print

ディレクトリ名のみが必要な場合は、-exec最初のディレクトリの後に別のディレクトリに入れることもできます(find最初のテスト後に停止)。

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -exec dirname {} \;

答え4

たぶんこれがうまくいくでしょうか?

comm -23 <(find -name "report.md" -printf '%h\n' | sort) <(find -name "report.pdf" -printf '%h\n' | sort)

関連情報