Tôi muốn in số ký tự trong mỗi dòng của tệp văn bản bằng lệnh unix. Tôi biết nó rất đơn giản với powershell
gc abc.txt | % {$_.length}
nhưng tôi cần lệnh unix.
Câu trả lời:
Sử dụng Awk.
awk '{ print length }' abc.txt
while IFS= read -r line; do echo ${#line}; done < abc.txt
Nó là POSIX, vì vậy nó sẽ hoạt động ở mọi nơi.
Chỉnh sửa: Đã thêm -r theo đề xuất của William.
Chỉnh sửa: Cẩn thận với việc xử lý Unicode. Bash và zsh, với ngôn ngữ được đặt chính xác, sẽ hiển thị số điểm mã, nhưng dấu gạch ngang sẽ hiển thị byte — vì vậy bạn phải kiểm tra xem trình bao của mình hoạt động như thế nào. Và dù sao thì cũng có nhiều định nghĩa khác về độ dài trong Unicode, vì vậy nó phụ thuộc vào những gì bạn thực sự muốn.
Chỉnh sửa: Tiền tố với IFS=
để tránh mất dấu cách ở đầu và cuối.
IFS=
trên read
lệnh khi muốn đọc dữ liệu tùy ý. Vì vậy IFS= read -r
. read
sử dụng IFS
để thực hiện tách từ và mặc dù tất cả các từ đã tách sau đó được dán lại với nhau vào một biến có sẵn ( line
), không có gì đảm bảo rằng chúng sẽ được dán lại cùng với tất cả các ký tự phân tách ban đầu mà chúng có hoặc chỉ một biến có thể khác những cái. Ví dụ, với IFS mặc định, dòng foo bar
có thể trở thành foo bar
, mất 7 khoảng trắng. (Giống như cách Stack Overflow làm mất các khoảng trắng liền kề trong chuỗi ví dụ đó trong nhận xét này).
IFS
nên được đặt ra, nhưng vấn đề khi nó không tinh tế hơn.
Tôi đã thử các câu trả lời khác được liệt kê ở trên, nhưng chúng vẫn còn rất xa so với các giải pháp tốt khi xử lý các tệp lớn - đặc biệt là khi kích thước của một dòng chiếm hơn ~ 1/4 RAM khả dụng.
Cả bash và awk slurp toàn bộ dòng, mặc dù đối với vấn đề này, nó không cần thiết. Bash sẽ xuất hiện lỗi khi một dòng quá dài, ngay cả khi bạn có đủ bộ nhớ.
Tôi đã triển khai một tập lệnh python cực kỳ đơn giản, khá không được tối ưu hóa mà khi được thử nghiệm với các tệp lớn (~ 4 GB mỗi dòng) không bị trượt và cho đến nay là một giải pháp tốt hơn những giải pháp được đưa ra.
Nếu đây là mã thời gian quan trọng để sản xuất, bạn có thể viết lại các ý tưởng trong C hoặc thực hiện tối ưu hóa tốt hơn trên lệnh gọi đọc (thay vì chỉ đọc một byte duy nhất tại một thời điểm), sau khi kiểm tra rằng đây thực sự là một nút cổ chai.
Mã giả định dòng mới là một ký tự dòng cấp, đây là một giả định tốt cho Unix, nhưng YMMV trên Mac OS / Windows. Đảm bảo tệp kết thúc bằng một dòng cấp dữ liệu để đảm bảo số lượng ký tự dòng cuối cùng không bị bỏ sót.
from sys import stdin, exit
counter = 0
while True:
byte = stdin.buffer.read(1)
counter += 1
if not byte:
exit()
if byte == b'\x0a':
print(counter-1)
counter = 0
Thử đi:
while read line
do
echo -e |wc -m
done <abc.txt
echo -e | wc -m
, phải không? Việc sử dụng các lệnh là vô ích; shell có thể đếm các ký tự trong một biến. Plus echo -e
hoàn toàn không tương thích và hoạt động ở một nửa số shell trong khi bắt đầu với một số trình tự thoát hoạt động ở một số khác và không có gì trong phần còn lại.