Làm cách nào để tôi có được tổng số dòng với `wc -l`?


12

Tôi đã thêm một bí danh git để cung cấp cho tôi số lượng các tệp cụ thể trong lịch sử của mình:

[alias]
lines = !lc() { git ls-files -z ${1} | xargs -0 wc -l; }; lc

Tuy nhiên, wc -lđang báo cáo nhiều tổng số, sao cho nếu tôi có hơn ~ 100 nghìn dòng, nó sẽ báo cáo tổng số cho chúng, sau đó tiếp tục. Đây là một ví dụ:

<100k dòng (đầu ra mong muốn)

$ git lines \*.xslt
  46 packages/NUnit-2.5.10.11092/doc/files/Summary.xslt
 232 packages/NUnit-2.5.10.11092/samples/csharp/_UpgradeReport_Files/UpgradeReport.xslt
 278 total

> 100k dòng (phải chuyển sang grep "total")

$ git lines \*.cs | grep "total"
 123569 total
 107700 total
 134796 total
 111411 total
  44600 total

Làm thế nào để tôi có được tổng số thực sự wc -l, không phải là một loạt các tổng số phụ?


Theo stackoverflow.com/questions/2501402/ Lỗi vấn đề là với xargs, không phải wc. Tôi vẫn quan tâm đến cách khắc phục nó và tôi không thấy một giải pháp tốt trong các câu trả lời.
Ehryk

3
Phiên bản wchỗ trợ của bạn có --files0-fromtùy chọn không? Sau đó, bạn có thể làm{ git ls-files -z ${1} | wc -l --files0-from=- ; }
Đánh dấu Plotnick

@MarkPlotnick Tôi nghĩ rằng nó xứng đáng là một câu trả lời.
terdon

Không. wc: unrecognized option '--files0-from=-'
Ehryk

Câu trả lời:


12

Hãy thử điều này và xin lỗi vì đã rõ ràng:

cat *.cs | wc -l

hoặc, với git:

git ls-files -z ${1} | xargs -0 cat | wc -l

Nếu bạn thực sự muốn đầu ra trông giống như wcđầu ra, với cả số lượng riêng lẻ và tổng, bạn có thể sử dụng awkđể thêm các dòng riêng lẻ:

git ls-files -z ${1} | xargs -0 wc -l |
awk '/^[[:space:]]*[[:digit:]]+[[:space:]]+total$/{next}
     {total+=$1;print}
     END {print total,"total"}'

Điều đó sẽ không được xếp hàng độc đáo như wcnó, trong trường hợp quan trọng với bạn. Để làm điều đó, bạn cần đọc toàn bộ đầu vào và lưu nó, tính toán tổng, sau đó sử dụng tổng để tính độ rộng trường trước khi sử dụng chiều rộng trường đó để in một đầu ra được định dạng của các dòng đã nhớ. Giống như các dự án cải tạo nhà, awkkịch bản không bao giờ thực sự hoàn thành.

(Lưu ý với các biên tập viên nhiệt tình: biểu thức chính quy trong awkđiều kiện đầu tiên là trong trường hợp có một tệp có tên bắt đầu bằng "tổng" và khoảng trắng; nếu không, điều kiện có thể đơn giản hơn nhiều $2 == "total".)


Điều đó không làm việc, nhưng nó chỉ xuất ra tổng số ( git ls-files -z ${1} | xargs -0 cat | wc -l). Tuy nhiên, tôi thiếu số lượng dòng trên mỗi tệp mà wc -l cung cấp như trong ví dụ đầu tiên của tôi ở trên. Bất kỳ cách nào để có được tốt nhất của cả hai thế giới ở đây?
Ehryk

Hoặc, nếu điều đó quá khó khăn, thì còn một công tắc như thế nào nếu nó phá vỡ nó: chỉ cần đưa ra tổng số, nếu không, hãy cung cấp cho mỗi tệp wc bình thường với tổng đầu ra?
Ehryk

@Ehryk: bạn có thể thực hiện hai lần, một lần theo cách bạn đang thực hiện grep -vđể bỏ tổng số dòng và một lần theo cách tôi đề xuất để có được tổng số. Hoặc bạn có thể thử giải pháp awk trong câu trả lời đã được chỉnh sửa,
rici

+1: "Giống như các dự án cải tạo nhà, các kịch bản awk không bao giờ thực sự hoàn thành."
Ehryk

Tiếng Anh> Tiếng Việt. Kết quả cuối cùng của tôi:git ls-files -z ${1} | xargs -0 wc -l | awk '/^[[:space:]]*[[:digit:]]+[[:space:]]+total$/{next} {total+=$1;print} END {print "\n Total:",total,"lines"}'
Ehryk

7

Nếu bạn đang chạy Linux, wccó lẽ bạn đến từ GNU Coreutils và có --files0-fromtùy chọn đọc tệp (hoặc stdin) có chứa một danh sách dài các tên tệp kết thúc NUL tùy ý để đếm. Các tài liệu coreutils GNU wc nói "này rất hữu ích khi danh sách các tên tập tin là rất lâu đến nỗi nó có thể vượt quá một giới hạn lệnh dài dòng. Trong trường hợp này, chạy wc qua xargs là không mong muốn vì nó chia tách danh sách thành miếng và làm cho in wc tổng cộng cho mỗi danh sách phụ thay vì toàn bộ danh sách. "

Vì vậy, hãy thử điều này:

lc() { git ls-files -z ${1} | wc -l --files0-from=- ; } 

Chỉnh sửa: Vì bạn wcđến từ thiên niên kỷ trước và không có tùy chọn đó, nên đây là một giải pháp di động hơn, giả sử bạn có awkvà không có bất kỳ tệp nào có tên là "tổng". Nó sẽ lọc đầu ra wc, bỏ qua bất kỳ totaldòng nào và thay vào đó tóm tắt chúng và in ra tổng số cuối cùng.

Một điều tôi không biết là liệu việc gitthực hiện bí danh sẽ có vấn đề với $1$2bên trong các trích dẫn đơn, cần được chuyển không thay đổi awk.

lc() {
  git ls-files -z ${1} |
  xargs -0 wc -l |
  awk 'BEGIN { total=0; } { if (NF==2 && $2 == "total") total += $1; else print; } END { print total, "total"; }' ;
}

Tôi không chạy linux, nó nằm trong dấu nhắc git bash của Git cho Windows msysgit.github.io (msysgit).
Ehryk

ĐỒNG Ý. Vì vậy, xargswcbạn đang chạy là từ Cygwin? Bạn có thể dán đầu ra của wc --version?
Đánh dấu Plotnick

Chúng không phải từ bản cài đặt đầy đủ của Cygwin:$ wc --version wc (GNU textutils) 2.0 Written by Paul Rubin and David MacKenzie. Copyright (C) 1999 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Ehryk

Nó có đầy đủ trên các cửa sổ thực thi,C:\Program Files (x86)\Git\bin\wc.exe
Ehryk

@Ehryk Msysgit là một cổng của các công cụ Linux, nhưng nó có xu hướng có các phiên bản cũ, vì vậy nó có thể không có --files0-from.
Gilles 'SO- ngừng trở nên xấu xa'

4

Vấn đề là xargsphân chia lệnh thành nhiều lần chạy, do đó, wcbáo cáo tổng số cho mỗi lần. Bạn có một vài lựa chọn, bạn có thể giữ mọi thứ theo cách của chúng và phân tích wcđầu ra:

git ls-files -z ${1} | xargs -0 wc -l | awk '/total/{k+=$1}END{print k,"total"}';

Bạn có thể cat các tập tin:

git ls-files -z ${1} | xargs -0 cat | wc -l

Hoặc bạn có thể bỏ qua xargshoàn toàn (điều chỉnh từ đây ):

unset files i; while IFS= read -r -d $'\0' name; do 
 files[i++]="$name"; 
done < <(git ls-files -z ${1} ) && wc -l "${files[@]}"

Điều đó sẽ bị phá vỡ nếu danh sách các tệp của bạn dài hơn ARG_MAX .


-1
j=0; for i in *.php *.js *.css; do let j+=`wc -l $i | awk {'print $1'}`; done; echo $j;
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.