Bagaimana cara menggunakan wc dan piping untuk menemukan berapa banyak file dan direktori dalam direktori tertentu?

10

Bagaimana saya bisa menggunakan penghitung kata ( wc) dan perpipaan untuk menghitung berapa banyak file atau direktori dalam /usr/bindirektori?

tunai
sumber
PR ini ?? Tidak masalah untuk meminta bantuan, identifikasi saja seperti itu, jika memang benar.
slm
ya itu tapi saya posting di sini untuk mendapatkan ide tentang cara mencapai sesuatu karena saya baru mengenal Linux dan itu bisa sangat rumit. Dan saya sudah memecahkan pertanyaan di atas dengan perintah ini
uang tunai
ls / bin / usr / bin | sortir | uniq | wc -
uang tunai
np. Tidak apa-apa untuk meminta bantuan! Cukup beri label sehingga orang tahu, semua orang di sini biasanya senang membantu orang yang mencoba mempelajari poin-poin penting Unix.
slm

Jawaban:

13

Salah satu pendekatan akan digunakan lsuntuk memberi kami daftar file, tetapi kami ingin daftar ini dijamin hanya menampilkan 1 file atau direktori per baris. The -1switch akan melakukan ini untuk kita.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Contoh

Buat data sampel di atas dalam direktori kosong.

$ mkdir dir{1..3}
$ touch file{A..C}

Periksa:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Sekarang untuk menghitung, Anda dapat menggunakan wc -luntuk menghitung jumlah baris, yang sesuai dengan file atau direktori dalam ls -1output.

$ ls -1 | wc -l
6

(Namun perlu dicatat bahwa itu tidak termasuk file yang tersembunyi)

Menghitung file atau direktori, tidak bersama-sama

Untuk menghitung file atau direktori, Anda perlu sedikit mengubah taktik Anda. Dalam hal ini saya akan menggunakan ls -lkarena ini menunjukkan apa itu direktori dan file apa.

Contoh

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Kemudian kita dapat menggunakan grepuntuk menyaring direktori atau tidak-direktori seperti:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Sekarang cukup gunakan wc -llagi untuk menghitung di atas:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

Meskipun, Anda dapat menghindari wcsama sekali, dan menggunakan grep's -cpilihan:

$ ls -l | grep -c '^d'

(Sekali lagi, file tersembunyi tidak termasuk. Perhatikan bahwa direktori dan reguler adalah dua jenis file. Ada lebih banyak lagi seperti pipa bernama, tautan simbolik, perangkat, soket ...).

Pengulangan

Jika Anda perlu menemukan file dan direktori secara rekursif di bawah /usr/binmaka Anda mungkin ingin mengubah taktik sepenuhnya dan menggunakan alat lain yang disebut find.

Contoh

$ find /usr/bin | wc -l
4632

(meskipun di atas /usr/binitu sendiri termasuk dalam hitungan)

Teknik yang sama yang saya gunakan di atas dapat digunakan lsuntuk melakukan sesuatu yang serupa tetapi lsumumnya bukan alat yang baik untuk mem-parsing output. finddi sisi lain dibangun untuk ini, dan menawarkan sakelar untuk menemukan file atau direktori.

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(perhatikan bahwa saat ini, findsudah termasuk file tersembunyi (kecuali .dan ..)).

baris baru?

Saya tidak pernah tahu mengapa karakter baris baru adalah karakter hukum untuk digunakan saat membuat nama file atau nama direktori. Jadi metode yang dibahas di atas menggunakan wcdan lstidak akan menentangnya, jadi gunakan metode itu dengan mengingatnya.

Contoh

Buat direktori & nama file dengan baris baru.

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls menunjukkannya dengan benar:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

Tetapi wcmenghitung direktori dan file yang berisi baris baru sebagai 2 item, bukan satu.

$ ls -1 | wc -l
10

Salah satu metode untuk mengatasi ini, jika menggunakan implementasi GNU findadalah dengan memanfaatkan findkemampuan untuk mencetak sesuatu yang lain di tempat setiap file yang ditemukannya dan kemudian menghitungnya.

Contoh

$ find . -printf . | wc -c
9

Di sini kami menemukan semua yang ada di direktori saat ini (kecuali ..), dan mencetak sebuah titik ( .) untuk masing-masing, dan kemudian menghitung titik menggunakan wckemampuan untuk menghitung byte alih-alih garis wc -c,.

Referensi

slm
sumber
Walaupun semua file di dalam /usr/binakan diformat dengan baik (dan juga tidak akan berisi spasi, jadi secara teknis Anda bahkan bisa adil echo * | wc -w), perlu dicatat bahwa semua ini akan merusak nama file yang mengandung baris baru.
evilsoup
@ evilsoup - tidak, saya tidak percaya ls -latau ls -1akan merusak b / c kita menghitung baris, bukan kata-kata! The findbisa pecah, tapi sekali lagi, kita menghitung garis bukan kata-kata.
slm
Maksud saya adalah bahwa ini akan (saya pikir, saya di Windows sekarang jadi saya tidak bisa menguji) pecah jika file berisi baris baru . Jadi touch $'foo\nbar'dalam direktori kosong diikuti oleh salah satu perintah Anda (katakanlah ls -1 | wc -l) akan melaporkan dua file daripada satu - karena satu file sejauh dua baris sejauh wcyang bersangkutan. Kecuali jika lsmengganti baris baru dengan beberapa karakter lain (saya pikir tidak, tapi sekali lagi saya tidak dalam posisi untuk menguji sekarang).
evilsoup
@ evilsoup - benar, baris baru char. adalah char legal. untuk nama file, dan metode tidak akan dapat bersaing dengan jenis nama file dengan benar.
slm
@StephaneChazelas - apakah wc -cada masalah saat menghitung periode?
slm
5

Jika Anda ingin mendapatkan rincian jumlah setiap jenis file secara rekursif di bawah beberapa dir, dengan GNU find, Anda bisa melakukan:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Di /usr/binsistem saya, itu memberi:

   3727 regular files
    710 symbolic links

Pada /dev:

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

Untuk symlink, jika Anda lebih suka menghitungnya sebagai jenis file yang mereka tuju alih-alih symbolic links, Anda dapat mengubahnya ke:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Yang sekarang memberi saya /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(symlink yang rusak adalah symlink ke file yang findtidak dapat menentukan jenisnya karena file tersebut tidak ada, atau berada di direktori yang Anda tidak memiliki akses ke atau ada loop dalam resolusi jalur file) Dalam kasus saya, 2 tempat symlink ke file yang sekarang hilang).

Tak satu pun dari mereka dihitung .dan ... Jika Anda ingin mereka dimasukkan (mengapa Anda mau?), Tidak ada cara lain findselain menganggap mereka ada di setiap direktori dan menghitungnya secara sistematis:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Yang kemudian memberi saya /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Jika Anda tidak memiliki akses ke GNU find, Anda dapat menulis ulang yang pertama sebagai:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

Sekarang, sebenarnya, kami tidak menghitung file tetapi entri direktori . Direktori seperti /usr/binbiasanya memiliki beberapa entri yang mengarah ke file yang sama. Misalnya, di sini, saya punya:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

Itu adalah 3 entri direktori (alias nama file alias tautan keras) ke file yang sama (satu dengan inode 672252. Untuk menghitung file alih-alih entri direktori dan dengan GNU finddan GNU uniq(mengabaikan .dan ..file yang toh merupakan tautan keras ke direktori lain):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

Pada saya /usr/bin, itu memberi:

   3711 regular files
    710 symbolic links
Stéphane Chazelas
sumber
0

Anda belum mengatakan jika Anda ingin semua file di bawah / usr / bin secara rekursif atau hanya di bawah tingkat pertama. Juga, bagaimana Anda akan mendapatkan kata-kata yang Anda hitung? Cara yang biasa untuk mengetahuinya adalah dengan menjalankan find ke wc. Seperti ini: find / usr / bin | wc-l Find akan menampilkan semua yang ada di sana, direktori & file. Wc-l akan menghitung semua garis dalam output find. Apakah ini tugas kelas? Tidak apa-apa jika itu tapi saya bertanya-tanya mengapa Anda membutuhkan info ini sehingga saya bisa menyesuaikan respon dengan lebih hati-hati. Tolong beri tahu saya jika Anda membutuhkan lebih banyak. Costa

cdr
sumber
0

Di bash, tanpa alat eksternal.

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

Di bash, tanpa alat eksternal dan rekursi.

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done
llua
sumber
Perhatikan bahwa yang kedua akan mengikuti symlink ketika berulang (dan menghitung symlink ke file biasa sebagai file biasa, dan symlink ke dir sebagai dir), tidak akan menghitung file dan direktori di direktori saat ini dan tidak akan menghitung .maupun ..entri. Anda mungkin ingin memisahkan file vs file biasa.
Stéphane Chazelas