Saya ingin secara rekursif mencari setiap *.pdf
file dalam direktori ~/foo
yang nama dasarnya cocok dengan nama direktori induk file.
Sebagai contoh, misalkan struktur direktori ~/foo
terlihat seperti ini
foo
├── dir1
│ ├── dir1.pdf
│ └── dir1.txt
├── dir2
│ ├── dir2.tex
│ └── spam
│ └── spam.pdf
└── dir3
├── dir3.pdf
└── eggs
└── eggs.pdf
Menjalankan perintah yang saya inginkan akan kembali
~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf
Apakah ini mungkin menggunakan find
atau utilitas inti lainnya? Saya menganggap ini bisa dilakukan dengan menggunakan -regex
opsi find
tapi saya tidak yakin bagaimana menulis pola yang benar.
Jawaban:
Dengan GNU
find
:-regextype egrep
gunakan regex style egrep..*/
cocok dengan sutradara grand parent.([^/]+)/
mencocokkan dir induk dalam suatu grup.\1\.pdf
gunakanbackreference
untuk mencocokkan nama file sebagai dir induk.memperbarui
Satu (saya sendiri) mungkin berpikir itu
.*
cukup serakah, tidak perlu dikecualikan/
dari pencocokan orang tua:Perintah di atas tidak akan berfungsi dengan baik, karena itu berarti
./a/b/a/b.pdf
:.*/
cocok./
(.+)/
cocoka/b/
\1.pdf
cocoka/b.pdf
sumber
find . -regex '.*/\([^/]*\)/\1\.pdf'
bahkan itu akan bekerja dengan BSDfind
.Varian loop tradisional
find .. -exec sh -c ''
untuk menggunakan konstruksi shell agar sesuai dengan nama dasar dan jalur langsung di atas akan dilakukan di bawah.Untuk rincian parameter ekspansi individu
file
berisi path lengkap.pdf
file yang dikembalikan darifind
perintah"${file##*/}"
hanya berisi bagian setelah yang terakhir/
yaitu hanya nama file"${file%/*}"
berisi path hingga final/
yaitu kecuali bagian nama samaran dari hasil"${path##*/}"
berisi bagian setelah yang terakhir/
daripath
variabel, yaitu path folder langsung di atas nama file"${base%.*}"
berisi bagian dari nama samaran dengan.pdf
ekstensi dihapusJadi jika nama samaran tanpa ekstensi cocok dengan nama folder langsung di atas, kami mencetak jalurnya.
sumber
Kebalikan dari jawaban Inian , yaitu mencari direktori, dan kemudian melihat apakah mereka memegang file dengan nama tertentu.
Yang berikut ini mencetak nama path dari file yang ditemukan relatif terhadap direktori
foo
:${dirpath##*/}
akan diganti oleh bagian nama file dari jalur direktori, dan bisa diganti oleh$(basename "$dirpath")
.Untuk orang yang menyukai sintaks hubung singkat:
Manfaat melakukannya dengan cara ini adalah Anda mungkin memiliki lebih banyak file PDF daripada direktori. Jumlah tes yang terlibat berkurang jika seseorang membatasi kueri dengan jumlah yang lebih kecil (jumlah direktori).
Misalnya, jika satu direktori berisi 100 file PDF, ini hanya akan mencoba untuk mendeteksi salah satu dari mereka daripada menguji nama-nama semua 100 file terhadap direktori.
sumber
dengan
zsh
:Waspadai bahwa sementara
**/
tidak akan mengikuti symlink,*/
akan.sumber
Itu tidak ditentukan, tetapi di sini adalah solusi tanpa ekspresi reguler jika ada yang tertarik.
Kita bisa menggunakan
find . -type f
untuk hanya mendapatkan file, lalu memanfaatkandirname
danbasename
menulis persyaratan. Utilitas memiliki perilaku berikut:basename
mengembalikan hanya nama file setelah yang terakhir/
:dirname
memberikan seluruh jalan ke final/
:Oleh karena itu,
basename $(dirname $file)
berikan direktori induk file.Larutan
Gabungkan yang di atas untuk membentuk conditional
"$(basename $file)" = "$(basename $(dirname $file))".pdf
, maka hanya cetak setiap hasil darifind
jika conditional mengembalikan true.Dalam contoh di atas, kami telah menambahkan direktori / file dengan spasi dalam nama untuk menangani kasus itu (terima kasih kepada @Kusalananda di komentar)
sumber
Final Thesis.pdf
(dengan spasi).Saya mengambil bash globbing, loop sederhana atas tes string setiap hari selama program Find . Panggil saya irasional, dan meskipun mungkin suboptimal kode sederhana seperti melakukan trik untuk saya: dapat dibaca dan digunakan kembali, bahkan memuaskan !. Izinkan saya menyarankan kombinasi:
• pesta globstar :
for f in ** ; do ...
** loop atas setiap file dalam direktori saat ini dan semua subfolder .. untuk memeriksa status globstar dalam sesi Anda saat ini:shopt -p globstar
. Untuk globstar mengaktifkan:shopt -s globstar
.• utlity "file" :
if [[ $(file "$f") =~ pdf ]]; then ...
untuk memeriksa format file aktual untuk pdf - lebih kuat daripada hanya menguji ekstensi file• basename, dirname : untuk membandingkan nama file dengan nama direktori tepat di atasnya.
basename
mengembalikan nama file -dirname
mengembalikan seluruh jalur direktori - menggabungkan dua fungsi untuk hanya mengembalikan satu direktori yang berisi file yang cocok. Saya menempatkan masing-masing dalam variabel ( _mydir dan _myf ) untuk kemudian melakukan tes sederhana menggunakan = ~ untuk pencocokan string.Satu subtilitas: hapus sembarang "titik" dalam nama file untuk menghindari pencocokan nama file dengan direktori saat ini yang pintasannya juga "." - Saya menggunakan subtitusi string langsung pada variabel _myf :
${_myf//./}
- tidak terlalu elegan tetapi berfungsi. Pertandingan positif akan kembali jalur masing-masing file - bersama-sama dengan path lengkap dari folder saat ini dengan mendahului output dengan:$(pwd)/
.Kode
sumber