Làm thế nào để sử dụng wc và đường ống để tìm có bao nhiêu tệp và thư mục trong một thư mục nhất định?


10

Làm cách nào tôi có thể sử dụng word counter ( wc) và piping để đếm xem có bao nhiêu tệp hoặc thư mục trong /usr/binthư mục?


Bài tập về nhà này ?? Bạn có thể yêu cầu giúp đỡ, chỉ cần xác định nó là như vậy, nếu có.
slm

đúng vậy nhưng tôi đăng lên đây để có ý tưởng về cách đạt được điều gì đó vì tôi mới biết về Linux và nó có thể rất phức tạp. Và tôi đã giải quyết câu hỏi trên bằng lệnh này
tiền mặt

ls / bin / usr / bin | sắp xếp | uniq | wc -
tiền mặt

np. Hoàn toàn ổn khi yêu cầu giúp đỡ! Chỉ cần gắn nhãn cho mọi người biết, mọi người ở đây thường sẵn lòng giúp đỡ những người đang cố gắng tìm hiểu những điểm tốt hơn của Unix.
slm

Câu trả lời:


13

Một cách tiếp cận là sử dụng lsđể cung cấp cho chúng tôi danh sách các tệp, nhưng chúng tôi muốn danh sách này được đảm bảo chỉ hiển thị 1 tệp hoặc thư mục trên mỗi dòng. Công -1tắc sẽ làm điều này cho chúng tôi.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Thí dụ

Tạo dữ liệu mẫu ở trên trong một thư mục trống.

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

Kiểm tra nó:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Bây giờ để đếm, bạn có thể sử dụng wc -lđể đếm số lượng dòng, tương ứng với một tệp hoặc thư mục trong ls -1đầu ra.

$ ls -1 | wc -l
6

(lưu ý tuy nhiên nó không bao gồm các tệp ẩn)

Đếm các tập tin hoặc thư mục, chỉ là không cùng nhau

Để đếm một trong hai tệp hoặc thư mục, bạn cần thay đổi chiến thuật của mình một chút. Trong trường hợp này tôi sẽ sử dụng ls -lvì nó hiển thị thư mục và tập tin aa là gì.

Thí dụ

$ 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

Sau đó, chúng ta có thể sử dụng grepđể lọc ra các thư mục hoặc không phải thư mục như vậy:

# 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

Bây giờ chỉ cần sử dụng wc -lmột lần nữa để đếm ở trên:

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

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

Mặc dù vậy, bạn có thể tránh wchoàn toàn, và sử dụng grep's -clựa chọn:

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

(một lần nữa, các tệp ẩn không được bao gồm. Lưu ý rằng thư mục và thông thường là hai loại tệp. Có nhiều loại giống như ống được đặt tên, liên kết tượng trưng, ​​thiết bị, ổ cắm ...).

Đệ quy

Nếu bạn cần tìm các tệp và thư mục theo cách đệ quy /usr/binthì bạn có thể muốn thay đổi hoàn toàn các chiến thuật và sử dụng một công cụ khác được gọi find.

Thí dụ

$ find /usr/bin | wc -l
4632

(mặc dù ở trên /usr/binchính nó được bao gồm trong số)

Các kỹ thuật tương tự tôi đã sử dụng ở trên có thể được sử dụng lsđể làm một cái gì đó tương tự nhưng lsnhìn chung không phải là một công cụ tốt để phân tích đầu ra. findmặt khác được xây dựng cho việc này và cung cấp các công tắc để tìm tệp hoặc thư mục.

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

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

(lưu ý rằng lần này, findbao gồm các tệp ẩn (ngoại trừ ...)).

dòng mới?

Tôi chưa bao giờ hiểu tại sao một ký tự dòng mới là một ký tự hợp pháp để sử dụng khi tạo tên tệp hoặc tên thư mục. Vì vậy, các phương pháp được thảo luận ở trên bằng cách sử dụng wclssẽ không tranh cãi với chúng, vì vậy hãy sử dụng chúng với ý nghĩ đó.

Thí dụ

Tạo một thư mục và tên tập tin với dòng mới.

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

ls cho họ thấy chính xác:

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

Nhưng wctính các thư mục và tệp chứa dòng mới là 2 mục chứ không phải một.

$ ls -1 | wc -l
10

Một phương pháp để giải quyết vấn đề này, nếu sử dụng triển khai GNU findlà sử dụng findkhả năng của một bản in khác thay cho mỗi tệp mà nó tìm thấy và sau đó đếm chúng.

Thí dụ

$ find . -printf . | wc -c
9

Ở đây chúng tôi tìm thấy mọi thứ trong thư mục hiện tại (ngoại trừ ..) và in một dấu chấm ( .) cho mỗi dấu chấm , sau đó đếm các dấu chấm bằng cách sử dụng wckhả năng đếm byte thay vì các dòng , wc -c.

Người giới thiệu


Mặc dù các tệp trong /usr/bintất cả sẽ được định dạng tốt (và cũng sẽ không chứa khoảng trắng, vì vậy về mặt kỹ thuật bạn thậm chí có thể chỉ echo * | wc -w), đáng chú ý là tất cả những thứ này sẽ phá vỡ tên tập tin có chứa dòng mới.
evilsoup

@evilsoup - không tôi không tin ls -lhoặc ls -1sẽ phá vỡ b / c chúng tôi đang đếm dòng, không phải từ! Có findthể phá vỡ, nhưng một lần nữa, chúng ta đang đếm các dòng không phải là từ.
slm

Ý tôi là điều này sẽ (tôi nghĩ rằng, tôi đang ở trên Windows ngay bây giờ vì vậy tôi không thể kiểm tra) sẽ phá vỡ nếu các tệp chứa dòng mới . Vì vậy, touch $'foo\nbar'trong một thư mục trống được theo sau bởi một trong các lệnh của bạn (giả sử ls -1 | wc -l) sẽ báo cáo hai tệp chứ không phải một - vì một tệp đó là hai dòng theo như wccó liên quan. Trừ khi lsthay thế các dòng mới bằng một số nhân vật khác (tôi không nghĩ vậy, nhưng một lần nữa tôi không ở vị trí để kiểm tra ngay bây giờ).
evilsoup

@evilsoup - đúng, char dòng mới. là một char hợp pháp. đối với tên tệp và các phương thức sẽ không thể xử lý chính xác các loại tên tệp đó.
slm

@StephaneChazelas - là wc -cmột vấn đề khi đếm thời gian?
slm

5

Nếu bạn muốn phân tích số lượng từng loại tệp theo đệ quy theo một số thư mục, với GNU find, bạn có thể làm:

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 (&)/'

Trên /usr/binhệ thống của tôi, điều đó mang lại:

   3727 regular files
    710 symbolic links

Vào /dev:

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

Đối với liên kết tượng trưng, ​​nếu bạn muốn tính chúng là loại tệp mà chúng trỏ đến chứ không phải symbolic links, bạn có thể thay đổi nó thành:

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 (&)/'

Mà bây giờ cho tôi /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(một liên kết tượng trưng bị hỏng là một liên kết tượng trưng đến một tệp findkhông thể xác định loại vì tệp không tồn tại hoặc nằm trong thư mục mà bạn không có quyền truy cập hoặc có một vòng lặp trong độ phân giải đường dẫn của tệp Trong trường hợp của tôi, đó là 2 nơi liên kết tượng trưng đến các tệp đã biến mất).

Không ai trong số đó .... Nếu bạn muốn bao gồm chúng (tại sao bạn lại như vậy?), Không có cách nào khác findngoài việc cho rằng chúng ở đó cho mọi thư mục và đếm chúng một cách có hệ thống:

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 (&)/'

Mà sau đó cho tôi /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Nếu bạn không có quyền truy cập vào GNU find, bạn có thể viết lại cái đầu tiên dưới dạng:

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

Bây giờ, nói đúng ra, chúng tôi đã không đếm các tập tin mà là các mục trong thư mục . Một thư mục như /usr/binthường có một vài mục trỏ đến cùng một tệp. Chẳng hạn, ở đây, tôi có:

$ 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

Đó là 3 mục nhập thư mục (còn gọi là tên tệp hay liên kết cứng) vào cùng một tệp (tệp có inode 672252. Để đếm tệp thay vì mục nhập thư mục và với GNU findvà GNU uniq(bỏ qua ...các tệp dù sao cũng là liên kết cứng đến các thư mục khác):

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 (&)/'

Theo tôi /usr/bin, điều đó mang lại:

   3711 regular files
    710 symbolic links

0

Bạn chưa nói nếu bạn muốn tất cả các tệp dưới / usr / bin đệ quy hoặc chỉ dưới cấp độ đầu tiên. Ngoài ra, làm thế nào bạn sẽ có được những từ mà bạn đang đếm? Cách thông thường để tìm hiểu là chạy tìm vào wc. Như thế này: find / usr / bin | wc -l Find sẽ liệt kê mọi thứ ở đó, thư mục và tập tin. Wc -l sẽ đếm tất cả các dòng trong đầu ra tìm. Đây có phải là một bài tập lớp? Sẽ ổn nếu có nhưng tôi đã tự hỏi tại sao bạn cần thông tin này để tôi có thể điều chỉnh phản hồi cẩn thận hơn. Xin vui lòng cho tôi biết nếu bạn cần thêm. Costa


0

Trong bash, không có công cụ bên ngoài.

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

Trong bash, không có công cụ bên ngoài và đệ quy.

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

Lưu ý rằng cái thứ hai sẽ theo các liên kết tượng trưng khi đệ quy (và đếm các liên kết tượng trưng cho các tệp thông thường như các tệp thông thường và các liên kết tượng trưng đến các thư mục dưới dạng thư mục), sẽ không tính các tệp và thư mục trong thư mục hiện tại và sẽ không tính .cả ..các mục nhập. Bạn có thể muốn phân biệt tệp so với tệp thông thường.
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.