Câu trả lời ngắn:
\ls -afq | wc -l
(Điều này bao gồm .
và ..
, vì vậy trừ 2.)
Khi bạn liệt kê các tệp trong một thư mục, ba điều phổ biến có thể xảy ra:
- Liệt kê tên tập tin trong thư mục Điều này là không thể bỏ qua: không có cách nào để đếm các tệp trong một thư mục mà không liệt kê chúng.
- Sắp xếp tên tập tin. Shell wildcards và
ls
lệnh làm điều đó.
- Gọi
stat
để lấy siêu dữ liệu về mỗi mục nhập thư mục, chẳng hạn như đó có phải là thư mục không.
# 3 là đắt nhất cho đến nay, bởi vì nó yêu cầu tải một nút cho mỗi tệp. Trong so sánh, tất cả các tên tệp cần thiết cho # 1 được lưu trữ gọn trong một vài khối. # 2 lãng phí một số thời gian CPU nhưng nó thường không phải là một bộ ngắt thỏa thuận.
Nếu không có dòng mới trong tên tệp, một đơn giản ls -A | wc -l
cho bạn biết có bao nhiêu tệp trong thư mục. Lưu ý rằng nếu bạn có bí danh ls
, điều này có thể kích hoạt một cuộc gọi đến stat
(ví dụ ls --color
hoặc ls -F
cần biết loại tệp, yêu cầu gọi đến stat
), vì vậy từ dòng lệnh, gọi command ls -A | wc -l
hoặc \ls -A | wc -l
để tránh bí danh.
Nếu có dòng mới trong tên tệp, liệu dòng mới có được liệt kê hay không phụ thuộc vào biến thể Unix. GNU coreutils và BusyBox mặc định hiển thị ?
cho một dòng mới, vì vậy chúng an toàn.
Gọi ls -f
để liệt kê các mục mà không sắp xếp chúng (# 2). Điều này tự động bật -a
(ít nhất là trên các hệ thống hiện đại). Các -f
tùy chọn là trong POSIX nhưng với tình trạng bắt buộc; hầu hết các triển khai đều hỗ trợ nó, nhưng BusyBox thì không. Tùy chọn -q
thay thế các ký tự không in được, bao gồm cả dòng mới bằng ?
; đó là POSIX nhưng không được BusyBox hỗ trợ, vì vậy hãy bỏ qua nếu bạn cần hỗ trợ BusyBox với chi phí vượt qua các tệp có tên chứa ký tự dòng mới.
Nếu thư mục không có thư mục con, thì hầu hết các phiên bản find
sẽ không gọi stat
các mục của nó (tối ưu hóa thư mục lá: thư mục có số lượng liên kết là 2 không thể có thư mục con, vì vậy find
không cần phải tìm siêu dữ liệu của các mục trừ khi điều kiện như -type
yêu cầu nó). Vì vậy, find . | wc -l
một cách di động, nhanh chóng để đếm các tệp trong một thư mục với điều kiện thư mục đó không có thư mục con và không có tên tệp nào chứa một dòng mới.
Nếu thư mục không có thư mục con nhưng tên tệp có thể chứa dòng mới, hãy thử một trong những thư mục này (thư mục thứ hai sẽ nhanh hơn nếu được hỗ trợ, nhưng có thể không đáng chú ý như vậy).
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
Mặt khác, không sử dụng find
nếu thư mục có thư mục con: thậm chí find . -maxdepth 1
gọi stat
trên mỗi mục (ít nhất là với GNU find và BusyBox find). Bạn tránh sắp xếp (# 2) nhưng bạn phải trả giá cho việc tra cứu inode (# 3) sẽ giết chết hiệu suất.
Trong shell không có công cụ bên ngoài, bạn có thể chạy đếm các tệp trong thư mục hiện tại với set -- *; echo $#
. Điều này bỏ lỡ các tệp chấm (các tệp có tên bắt đầu .
) và báo cáo 1 thay vì 0 trong một thư mục trống. Đây là cách nhanh nhất để đếm các tệp trong các thư mục nhỏ vì nó không yêu cầu bắt đầu một chương trình bên ngoài, nhưng (ngoại trừ trong zsh) lãng phí thời gian cho các thư mục lớn hơn do bước sắp xếp (# 2).
Trong bash, đây là một cách đáng tin cậy để đếm các tệp trong thư mục hiện tại:
shopt -s dotglob nullglob
a=(*)
echo ${#a[@]}
Trong ksh93, đây là một cách đáng tin cậy để đếm các tệp trong thư mục hiện tại:
FIGNORE='@(.|..)'
a=(~(N)*)
echo ${#a[@]}
Trong zsh, đây là một cách đáng tin cậy để đếm các tệp trong thư mục hiện tại:
a=(*(DNoN))
echo $#a
Nếu bạn có mark_dirs
tùy chọn được đặt, hãy đảm bảo tắt nó : a=(*(DNoN^M))
.
Trong bất kỳ shell POSIX nào, đây là một cách đáng tin cậy để đếm các tệp trong thư mục hiện tại:
total=0
set -- *
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- .[!.]*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
set -- ..?*
if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
echo "$total"
Tất cả các phương thức này sắp xếp tên tệp, ngoại trừ zsh.
ls -l|wc -l
sẽ bị tắt bởi một do tổng số khối trong dòngls -l
đầu ra đầu tiên