レポートディレクトリが多く、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
C
h
report.md
**/
D
e
[[ -e $REPLY:r.pdf ]]
^
$REPLY:r
r
$REPLY
組み込みの引数とBourne様シェル(GNUを含む)の実装を許可すると、find
次のことができます。find
{}
-exec
bash
find . -type d -exec test -e '{}/report.md' \; \
! -exec test -e '{}/report.pdf' \; -print
test
ただし、これはディレクトリごとに最大2つのコマンドを実行することを意味します。
内蔵機能を使用すると、次の方法でこれらの問題を回避できますbosh
。find
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
(最近のほとんど)では、見つかったディレクトリのリストを処理するためにできるだけ少ない回数で呼び出す必要があるため、比較的効率的です。[
printf
sh
find
答え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)