Gunakan perintah find tetapi kecualikan file dalam dua direktori

88

Saya ingin mencari file yang diakhiri dengan _peaks.bed, tetapi mengecualikan file di folder tmpdan scripts.

Perintah saya seperti ini:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

Tapi itu tidak berhasil. File di dalam tmpdan scriptfolder akan tetap ditampilkan.

Apakah ada yang punya ide tentang ini?

Hanfei Sun
sumber

Jawaban:

192

Inilah cara Anda dapat menentukannya dengan find:

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

Penjelasan:

  • find . - Mulai temukan dari direktori kerja saat ini (secara rekursif secara default)
  • -type f- Tentukan findbahwa Anda hanya ingin file dalam hasil
  • -name "*_peaks.bed" - Cari file dengan nama yang diakhiri dengan _peaks.bed
  • ! -path "./tmp/*" - Kecualikan semua hasil yang jalurnya dimulai dengan ./tmp/
  • ! -path "./scripts/*" - Juga kecualikan semua hasil yang jalurnya dimulai dengan ./scripts/

Menguji Solusi:

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

Anda cukup dekat, -nameopsi hanya mempertimbangkan nama dasar, -pathsedangkan seluruh jalur =)

sampson-chen
sumber
Kerja bagus. Namun, Anda lupa salah satu hal yang diinginkan OP, untuk menemukan file yang diakhiri dengan _peaks.bed.
alex
2
Ini menggunakan sejumlah ekstensi di GNU find, tetapi karena pertanyaannya diberi tag Linux, itu tidak menjadi masalah. Jawaban yang bagus.
Jonathan Leffler
1
Catatan singkat: jika Anda menggunakan .pada prompt pencarian awal, Anda harus menggunakannya di setiap jalur yang Anda kecualikan. Pencocokan jalur cukup ketat, tidak melakukan pencarian kabur. Jadi jika Anda menggunakannya find / -type f -name *.bed" ! -path "./tmp/"tidak akan berhasil. Anda harus ! -path "/tmp"membuatnya bahagia.
peelman
3
Penting untuk diperhatikan bahwa * itu penting. $ ! -path "./directory/*"
Thomas Bennett
3
Menurut halaman manual: "Untuk mengabaikan seluruh pohon direktori, gunakan -prunedaripada memeriksa setiap file di pohon." Jika direktori Anda yang dikecualikan berjalan sangat dalam atau memiliki banyak file dan Anda peduli dengan kinerjanya, gunakan -pruneopsi sebagai gantinya.
thdoan
8

Inilah salah satu cara Anda dapat melakukannya ...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"
alex
sumber
2
Ini bermanfaat untuk bekerja dengan versi apa pun find, bukan hanya dengan GNU find. Namun, pertanyaannya adalah men-tag Linux sehingga tidak kritis.
Jonathan Leffler
2

Menggunakan

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

atau

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

atau

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

Urutan itu penting. Ini mengevaluasi dari kiri ke kanan. Selalu mulai dengan pengecualian jalur.

Penjelasan

Jangan gunakan -not(atau !) untuk mengecualikan seluruh direktori. Gunakan -prune. Seperti yang dijelaskan di manual:

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

dan di GNU temukan manual:

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

Memang, jika Anda menggunakan -not -path "./pathname", find akan mengevaluasi ekspresi untuk setiap node di bawah "./pathname".

menemukan ekspresi hanyalah evaluasi kondisi.

  • \( \)- Operasi grup (Anda dapat menggunakan -path "./tmp" -prune -o -path "./scripts" -prune -o, tetapi lebih bertele-tele).
  • -path "./script" -prune- jika -pathkembali benar dan adalah sebuah direktori, kembali benar untuk direktori tersebut dan jangan tidak turun ke dalamnya.
  • -path "./script" ! -prune- dievaluasi sebagai (-path "./script") AND (! -prune). Ini mengembalikan "selalu benar" dari prune menjadi selalu salah. Ini menghindari pencetakan "./script"sebagai korek api.
  • -path "./script" -prune -false- karena -pruneselalu mengembalikan nilai true, Anda dapat mengikutinya dengan -falsemelakukan hal yang sama dari !.
  • -o- ATAU operator. Jika tidak ada operator yang ditentukan di antara dua ekspresi, defaultnya adalah operator AND.

Oleh karena itu, \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -printdiperluas menjadi:

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

Cetakan penting di sini karena tanpa itu diperluas menjadi:

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-printditambahkan oleh find - itulah sebabnya sebagian besar waktu, Anda tidak perlu menambahkannya dalam ekspresi Anda. Dan karena -prunemengembalikan nilai true, itu akan mencetak "./script" dan "./tmp".

Hal ini tidak perlu dilakukan di tempat lain karena kami beralih -pruneuntuk selalu mengembalikan false.

Petunjuk: Anda dapat menggunakan find -D opt expr 2>&1 1>/dev/nulluntuk melihat bagaimana itu dioptimalkan dan diperluas,
find -D search expr 2>&1 1>/dev/nulluntuk melihat jalur mana yang diperiksa.

f380cedric.dll
sumber
0

Cobalah sesuatu seperti

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

dan jangan terlalu terkejut jika saya salah paham. Jika tujuannya adalah seorang exec (bukan print), gantikan saja.

DrC
sumber
0

bagi saya, solusi ini tidak berfungsi pada perintah exec dengan find, tidak benar-benar tahu mengapa, jadi solusi saya adalah

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

Penjelasan: sama seperti sampson-chen satu dengan tambahan

-prune - abaikan jalur prosedural ...

-o - Kemudian jika tidak ada hasil yang cocok, (pangkas direktori dan cetak hasil yang tersisa)

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz
al3x2ndru.dll
sumber
Jawaban yang diterima tidak berhasil, tetapi ini berhasil. Menggunakan prune find . -path ./scripts -prune -name '*_peaks.bed' -type f,. Tidak yakin bagaimana mengecualikan beberapa direktori. Ini juga mencantumkan direktori tingkat atas yang dikecualikan meskipun typeditentukan. Mengecualikan melalui Grep tampaknya lebih mudah kecuali Anda ingin menggunakan prune untuk mempercepat operasi pencarian.
Mohnish
Saya mengalami masalah dalam mengecualikan beberapa direktori, juga, tetapi komentar di atas memberi saya jawaban yang berhasil. Saya menggunakan beberapa contoh '-tidak-jalur' dan di setiap ekspresi jalur saya menyertakan awalan lengkap seperti yang digunakan pada parameter pertama untuk 'menemukan' dan mengakhiri masing-masing dengan tanda bintang (dan menghindari titik apa pun).
jetset
0

Anda dapat mencoba di bawah ini:

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'
Jacky Jiang
sumber
2
Pada pertanyaan lama seperti itu (4 tahun!) Anda ingin menjelaskan mengapa jawaban baru ini lebih baik atau berbeda, bukan hanya kode "dump".
Nic3500