Saya ingin tahu berapa banyak file biasa memiliki ekstensi .c
dalam struktur direktori besar yang kompleks, dan juga berapa banyak direktori file ini tersebar. Output yang saya inginkan hanyalah dua angka itu.
Saya telah melihat pertanyaan ini tentang cara mendapatkan jumlah file, tetapi saya perlu tahu jumlah direktori file juga.
- Nama file saya (termasuk direktori) mungkin memiliki karakter apa saja; mereka mungkin mulai dengan
.
atau-
dan memiliki spasi atau baris baru. - Saya mungkin memiliki beberapa symlink yang namanya diakhiri dengan
.c
, dan symlink ke direktori. Saya tidak ingin symlink diikuti atau dihitung, atau setidaknya saya ingin tahu apakah dan kapan mereka dihitung. - Struktur direktori memiliki banyak tingkatan dan direktori tingkat atas (direktori kerja) memiliki setidaknya satu
.c
file di dalamnya.
Saya buru-buru menulis beberapa perintah di shell (Bash) untuk menghitungnya sendiri, tapi saya rasa hasilnya tidak akurat ...
shopt -s dotglob
shopt -s globstar
mkdir out
for d in **/; do
find "$d" -maxdepth 1 -type f -name "*.c" >> out/$(basename "$d")
done
ls -1Aq out | wc -l
cat out/* | wc -l
Ini menghasilkan keluhan tentang pengalihan ambigu, melewatkan file di direktori saat ini, dan tersandung pada karakter khusus (misalnya, output yang diarahkan find
mencetak baris baru dalam nama file ) dan menulis sejumlah besar file kosong (oops).
Bagaimana saya dapat dengan andal menyebutkan .c
file - file saya dan direktori yang mengandungnya?
Jika itu membantu, berikut adalah beberapa perintah untuk membuat struktur pengujian dengan nama dan symlink yang buruk:
mkdir -p cfiles/{1..3}/{a..b} && cd cfiles
mkdir space\ d
touch -- i.c -.c bad\ .c 'terrible
.c' not-c .hidden.c
for d in space\ d 1 2 2/{a..b} 3/b; do cp -t "$d" -- *.c; done
ln -s 2 dirlink
ln -s 3/b/i.c filelink.c
Dalam struktur yang dihasilkan, 7 direktori berisi .c
file, dan 29 file biasa diakhiri dengan .c
(jika dotglob
tidak aktif ketika perintah dijalankan) (jika saya salah hitung, beri tahu saya). Ini adalah angka yang saya inginkan.
Silahkan tidak menggunakan tes khusus ini.
NB: Jawaban dalam bahasa apa pun atau bahasa lain akan diuji & dihargai oleh saya. Jika saya harus menginstal paket baru, tidak ada masalah. Jika Anda tahu solusi GUI, saya mendorong Anda untuk berbagi (tapi saya mungkin tidak akan menginstal sejauh DE untuk mengujinya) :) Saya menggunakan Ubuntu MATE 17.10.
Jawaban:
Saya belum memeriksa hasilnya dengan symlink tetapi:
find
perintah mencetak nama direktori masing-masing.c
file yang ditemukan.sort | uniq -c
akan memberi kita berapa banyak file di setiap direktori (sort
mungkin tidak perlu di sini, tidak yakin)sed
, saya mengganti nama direktori dengan1
, sehingga menghilangkan semua karakter aneh yang mungkin, hanya dengan hitungan dan1
sisanyatr
d
sini pada dasarnya sama denganNR
. Saya bisa saja menghilangkan memasukkan1
dalamsed
perintah, dan hanya dicetak diNR
sini, tapi saya pikir ini sedikit lebih jelas.Hingga
tr
, data dibatasi oleh NUL, aman terhadap semua nama file yang valid.Dengan zsh dan bash, Anda dapat menggunakan
printf %q
untuk mendapatkan string yang dikutip, yang tidak memiliki baris baru di dalamnya. Jadi, Anda mungkin dapat melakukan sesuatu seperti:Namun, meskipun
**
seharusnya tidak memperluas untuk symlink ke direktori , saya tidak bisa mendapatkan output yang diinginkan pada bash 4.4.18 (1) (Ubuntu 16.04).Tapi zsh bekerja dengan baik, dan perintahnya dapat disederhanakan:
D
memungkinkan glob ini untuk memilih file titik,.
memilih file biasa (jadi, bukan symlink), dan:h
hanya mencetak jalur direktori dan bukan nama file (sepertifind
itu%h
) (Lihat bagian tentang Pembuatan dan Pengubah Nama File ). Jadi dengan perintah awk kita hanya perlu menghitung jumlah direktori unik yang muncul, dan jumlah baris adalah jumlah file.sumber
29 7
. Jika saya menambahkan-L
untukfind
, yang berlangsung hingga41 10
. Output mana yang Anda butuhkan?Python memiliki
os.walk
, yang membuat tugas-tugas seperti ini mudah, intuitif, dan secara otomatis kuat bahkan dalam menghadapi nama file aneh seperti yang mengandung karakter baris baru. Python 3 script ini, yang saya awalnya diumumkan di chat , dimaksudkan untuk dijalankan di direktori saat ini (tapi itu tidak harus berada di direktori saat ini, dan Anda dapat mengubah apa jalan itu lolos keos.walk
):Itu mencetak jumlah direktori yang secara langsung mengandung setidaknya satu file yang namanya berakhir
.c
, diikuti oleh spasi, diikuti oleh jumlah file yang namanya berakhir.c
. File "tersembunyi" - yaitu, file yang namanya dimulai dengan.
--adalah termasuk, dan direktori tersembunyi juga dilintasi.os.walk
secara rekursif melintasi hierarki direktori. Itu menyebutkan semua direktori yang secara rekursif dapat diakses dari titik awal yang Anda berikan, menghasilkan informasi tentang masing-masing sebagai tupel dari tiga nilairoot, dirs, files
,. Untuk setiap direktori yang dilaluinya (termasuk yang pertama yang namanya Anda berikan):root
memegang pathname dari direktori itu. Perhatikan bahwa ini sama sekali tidak terkait dengan "direktori root" sistem/
(dan juga tidak terkait/root
) meskipun itu akan pergi ke mereka jika Anda mulai di sana. Dalam hal ini,root
mulai di jalur.
--yaitu, direktori saat ini - dan kemana-mana di bawahnya.dirs
menyimpan daftar nama path dari semua subdirektori dari direktori yang namanya disimpanroot
.files
memegang daftar nama path dari semua file yang berada di direktori yang namanya saat ini disimpanroot
tetapi itu bukan direktori sendiri. Perhatikan bahwa ini termasuk jenis file lain selain file biasa, termasuk tautan simbolik, tetapi sepertinya Anda tidak mengharapkan entri seperti itu berakhir.c
dan tertarik melihat yang melakukannya.Dalam hal ini, saya hanya perlu memeriksa elemen ketiga dari tuple,
files
(yang saya sebutfs
dalam naskah). Sepertifind
perintah, Pythonos.walk
melintasi subdirektori untuk saya; satu-satunya hal yang harus saya periksa sendiri adalah nama-nama file yang masing-masing berisi. Tidak sepertifind
perintah, meskipun,os.walk
secara otomatis memberi saya daftar nama file tersebut.Skrip itu tidak mengikuti tautan simbolis. Anda sangat mungkin tidak ingin symlink diikuti untuk operasi seperti itu, karena mereka dapat membentuk siklus, dan karena bahkan jika tidak ada siklus, file dan direktori yang sama dapat dilalui dan dihitung beberapa kali jika mereka dapat diakses melalui symlink yang berbeda.
Jika Anda memang ingin
os.walk
mengikuti symlink - yang biasanya tidak Anda lakukan - maka Anda bisa meneruskannyafollowlinks=true
. Artinya, alih-alih menulisos.walk('.')
Anda bisa menulisos.walk('.', followlinks=true)
. Saya tegaskan bahwa Anda jarang menginginkan itu, terutama untuk tugas seperti ini di mana Anda secara rekursif menghitung seluruh struktur direktori, tidak peduli seberapa besar itu, dan menghitung semua file di dalamnya yang memenuhi beberapa persyaratan.sumber
Temukan + Perl:
Penjelasan
The
find
perintah akan menemukan file biasa (sehingga tidak ada symlink atau direktori) dan kemudian mencetak nama direktori mereka berada di (%h
) diikuti oleh\0
.perl -0 -ne
: baca input baris demi baris (-n
) dan terapkan skrip yang diberikan oleh-e
untuk setiap baris. The-0
menetapkan garis pemisah input ke\0
sehingga kita dapat membaca masukan nol-koma.$k{$_}++
:$_
adalah variabel khusus yang mengambil nilai dari baris saat ini. Ini digunakan sebagai kunci untuk hash%k
, yang nilainya berapa kali setiap baris input (nama direktori) terlihat.}{
: ini adalah cara penulisan singkatEND{}
. Setiap perintah setelah}{
akan dieksekusi sekali, setelah semua input telah diproses.print scalar keys %k, " $.\n"
:keys %k
mengembalikan array kunci dalam hash%k
.scalar keys %k
memberikan jumlah elemen dalam array itu, jumlah direktori yang terlihat. Ini dicetak bersama dengan nilai saat ini dari$.
, variabel khusus yang menyimpan nomor baris input saat ini. Karena ini dijalankan di akhir, nomor baris input saat ini akan menjadi jumlah baris terakhir, sehingga jumlah baris terlihat sejauh ini.Anda dapat memperluas perintah perl untuk ini, untuk kejelasan:
sumber
Inilah saran saya:
Script pendek ini membuat tempfile, menemukan setiap file di dalam dan di bawah direktori saat ini berakhir
.c
dan menulis daftar ke tempfile.grep
kemudian digunakan untuk menghitung file (mengikuti Bagaimana saya bisa mendapatkan jumlah file dalam direktori menggunakan baris perintah? ) dua kali: Kali kedua, direktori yang terdaftar beberapa kali dihapus menggunakansort -u
setelah menelanjangi nama file dari setiap baris menggunakansed
.Ini juga berfungsi dengan baik pada baris baru dalam nama file:
grep -c /
hanya menghitung baris dengan garis miring dan oleh karena itu hanya mempertimbangkan baris pertama dari nama file multi-baris dalam daftar.Keluaran
sumber
Shellscript kecil
Saya sarankan bash shellscript kecil dengan dua baris perintah utama (dan variabel
filetype
untuk membuatnya mudah untuk beralih untuk mencari jenis file lainnya).Itu tidak mencari atau di symlink, hanya file biasa.
Verbose shellscript
Ini adalah versi yang lebih verbose yang juga mempertimbangkan tautan simbolik,
Uji keluaran
Dari shellscript pendek:
Dari verbose shellscript:
sumber
Perl sederhana satu liner:
Atau lebih sederhana dengan
find
perintah:Jika Anda suka bermain golf dan memiliki Perl terbaru (seperti yang kurang dari satu dekade):
sumber
Pertimbangkan untuk menggunakan
locate
perintah yang jauh lebih cepat daripadafind
perintah.Berjalan pada data uji
Terima kasih kepada Muru atas jawabannya untuk membantu saya melucuti tautan simbolik dari jumlah file dalam jawaban Unix & Linux .
Terima kasih kepada Terdon untuk jawabannya
$PWD
(tidak diarahkan pada saya) dalam jawaban Unix & Linux .Jawaban asli di bawah ini dirujuk oleh komentar
Bentuk pendek:
sudo updatedb
Perbarui basis data yang digunakan denganlocate
perintah jika.c
file dibuat hari ini atau jika Anda telah menghapus.c
file hari ini.locate -cr "$PWD.*\.c$"
temukan semua.c
file di direktori saat ini dan itu adalah anak-anak ($PWD
). Alih-alih mencetak nama file, dan jumlah cetak dengan-c
argumen. Ther
menspesifikasikan regex bukan default*pattern*
yang cocok yang dapat menghasilkan terlalu banyak hasil.locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
. Temukan semua*.c
file di direktori saat ini dan di bawah ini. Hapus nama file dengansed
hanya menyisakan nama direktori. Hitung jumlah file di setiap direktori menggunakanuniq -c
. Hitung jumlah direktori denganwc -l
.Mulai di direktori saat ini dengan satu-liner
Perhatikan bagaimana jumlah file dan jumlah direktori telah berubah. Saya percaya semua pengguna memiliki
/usr/src
direktori dan dapat menjalankan perintah di atas dengan jumlah berbeda tergantung pada jumlah kernel yang diinstal.Bentuk panjang:
Bentuk panjang mencakup waktu sehingga Anda dapat melihat seberapa cepat
locate
telah berakhirfind
. Bahkan jika Anda harus menjalankannyasudo updatedb
beberapa kali lebih cepat daripada satufind /
.Catatan: Ini semua file di SEMUA drive dan partisi. yaitu kita dapat mencari perintah Windows juga:
Saya memiliki tiga partisi Windows 10 NTFS yang terpasang secara otomatis
/etc/fstab
. Sadarilah menemukan tahu segalanya!Jumlah Menarik:
Dibutuhkan 15 detik untuk menghitung 1.637.135 file di 286.705 direktori. YMMV.
Untuk perincian terperinci tentang
locate
penanganan regex perintah (tampaknya tidak diperlukan dalam T&J ini tetapi digunakan untuk berjaga-jaga) silakan baca ini: Gunakan "cari" di bawah direktori tertentu?Bacaan tambahan dari artikel terbaru:
sumber
.c
(perhatikan bahwa itu akan pecah jika ada file bernama-.c
di direktori saat ini karena Anda tidak mengutip*.c
) dan kemudian akan mencetak semua direktori dalam sistem, terlepas dari apakah mereka berisi file .c.~/my_c_progs/*.c
. Ini menghitung 638 direktori dengan.c
program, total direktori ditampilkan nanti sebagai286,705
. Saya akan merevisi jawaban untuk kutipan ganda `" * .c ". Terima kasih atas tipnya.locate -r "/path/to/dir/.*\.c$"
, tetapi itu tidak disebutkan di mana pun dalam jawaban Anda. Anda hanya memberikan tautan ke jawaban lain yang menyebutkan ini tetapi tanpa penjelasan tentang bagaimana menyesuaikannya untuk menjawab pertanyaan yang diajukan di sini. Seluruh jawaban Anda difokuskan pada bagaimana cara menghitung jumlah total file dan direktori pada sistem, yang tidak relevan dengan pertanyaan yang diajukan yaitu "bagaimana saya bisa menghitung jumlah file .c, dan jumlah direktori yang mengandung. file dalam direktori spesifik ". Juga, nomor Anda salah, coba contoh di OP.$PWD
variabel: unix.stackexchange.com/a/188191/200094$PWD
itu tidak mengandung karakter yang mungkin spesial di regex