Pertanyaan Bagaimana mengecualikan direktori di temukan. perintah


Saya mencoba menjalankan perintah find untuk semua file JavaScript, tetapi bagaimana cara mengecualikan direktori tertentu?

Berikut ini kode find yang kami gunakan.

for file in $(find . -name '*.js'); do java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file; done

903
2017-11-17 22:57


asal


Jawaban:


Gunakan sakelar prana, misalnya jika Anda ingin mengecualikan misc direktori tambahkan saja -path ./misc -prune -o ke perintah find Anda:

find . -path ./misc -prune -o -name '*.txt' -print

Berikut ini contoh dengan beberapa direktori:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

Di sini kita mengecualikan dir1, dir2 dan dir3, karena dalam find ekspresi itu adalah tindakan, yang bertindak berdasarkan kriteria -path dir1 -o -path dir2 -o -path dir3 (jika dir1 atau dir2 atau dir3), ANDED with type -d. Tindakan selanjutnya adalah -o print, cukup cetak.


701
2017-11-17 23:00



Jika -prune tidak berfungsi untuk Anda, ini akan:

find -name "*.js" -not -path "./directory/*"

1518
2018-04-01 01:26



Saya menemukan alasan berikut ini lebih mudah daripada solusi lain yang diusulkan:

find build -not \( -path build/external -prune \) -name \*.js

Ini berasal dari kasus penggunaan yang sebenarnya, di mana saya perlu memanggil yui-compressor pada beberapa file yang dihasilkan oleh wintersmith, tetapi meninggalkan file lain yang perlu dikirim apa adanya.

Dalam \( dan \) adalah ekspresi yang akan cocok persis  build/external (itu akan tidak cocok jika Anda melakukannya find ./build, misalnya - Anda perlu mengubahnya menjadi ./build/external dalam hal ini), dan akan, pada kesuksesan, hindari melintasi apa pun di bawah ini. Ini kemudian dikelompokkan sebagai ekspresi tunggal dengan kurung lepas, dan diawali dengan -not yang akan membuat find lewati apa pun yang dicocokkan dengan ekspresi itu.

Orang mungkin bertanya jika menambahkan -not tidak akan membuat semua file lain disembunyikan oleh -prune muncul kembali, dan jawabannya tidak. Jalan -prune berfungsi adalah apa pun yang, begitu tercapai, file di bawah direktori itu akan diabaikan secara permanen.

Itu juga mudah diperluas untuk menambahkan pengecualian tambahan. Sebagai contoh:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

341
2018-05-16 19:01



Jelas ada beberapa kebingungan di sini seperti apa sintaks yang diinginkan untuk melewati suatu direktori.

Opini GNU

To ignore a directory and the files under it, use -prune

Dari halaman manual GNU temukan

Pemikiran

-prune berhenti find dari turun ke direktori. Hanya menentukan -not -path masih akan turun ke dalam dilewati direktori, tapi -not -path akan salah kapanpun find menguji setiap file.

Masalah dengan -prune

-prune melakukan apa yang dimaksudkan untuk itu, tetapi masih ada beberapa hal yang harus Anda perhatikan saat menggunakannya.

  1. find mencetak direktori yang dipangkas.

    • BENAR Itu perilaku yang dimaksudkan, itu hanya tidak turun ke dalamnya. Untuk menghindari pencetakan direktori sama sekali, gunakan sintaks yang secara logis menghilangkannya.
  2. -prune hanya bekerja dengan -print dan tidak ada tindakan lain.

    • TIDAK BENAR. -prune berfungsi dengan tindakan apa pun kecuali -delete. Mengapa tidak berfungsi dengan menghapus? Untuk -delete untuk bekerja, menemukan kebutuhan untuk melintasi direktori dalam urutan DFS, karena -deletepertama akan menghapus daun, kemudian orang tua dari daun, dll ... Tapi untuk menentukan -prune agar masuk akal, find perlu menekan direktori dan berhenti turun, yang jelas tidak masuk akal -depth atau -delete di.

Kinerja

Saya membuat tes sederhana dari tiga jawaban teratas atas jawaban atas pertanyaan ini (diganti -printdengan -exec bash -c 'echo $0' {} \; untuk menampilkan contoh tindakan lain). Hasilnya di bawah

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

Kesimpulan

Kedua sintaks f10bit dan Sintaks Daniel C. Sobral mengambil 10-25ms untuk menjalankan rata-rata. Sintaks GetFree, yang tidak digunakan -prune, mengambil 865ms. Jadi, ya ini adalah contoh yang agak ekstrim, tetapi jika Anda peduli tentang waktu berjalan dan melakukan apa pun yang jauh intensif, Anda harus menggunakannya -prune.

Catatan Sintaks Daniel C. Sobral melakukan yang lebih baik dari keduanya -prune sintaksis; tapi, saya sangat curiga ini adalah hasil dari beberapa caching sebagai pengalihan urutan di mana keduanya berlari menghasilkan hasil yang berlawanan, sedangkan versi non-prune selalu paling lambat.

Test Script

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

153
2017-07-04 00:21



Salah satu pilihannya adalah mengecualikan semua hasil yang mengandung nama direktori dengan grep. Sebagai contoh:

find . -name '*.js' | grep -v excludeddir

44
2017-11-17 23:01



Saya lebih suka -not notasi ... lebih mudah dibaca:

find . -name '*.js' -and -not -path directory

37
2017-11-17 23:22



Gunakan opsi-prune. Jadi, sesuatu seperti:

find . -type d -name proc -prune -o -name '*.js'

'-type d -name proc -prune' hanya mencari direktori yang bernama proc untuk dikecualikan.
The '-o' adalah operator 'ATAU'.


17
2017-11-17 23:01



Ini adalah format yang saya gunakan untuk mengecualikan beberapa jalur:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

Saya menggunakan ini untuk menemukan semua file tidak di jalur ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

13
2018-01-18 17:06



Ini adalah satu-satunya yang berhasil untukku.

Mencari "NameOfFile" tidak termasuk "Direktori". Berikan penekanan pada bintang-bintang *.

find / -name NameOfFile ! -path '*/Directory/*'

10
2018-03-15 10:02