Cấm wc -c -và và wc -m Lệnh trong linux


24

Tôi có một tệp văn bản, nội dung của nó là:

i k k

Khi tôi sử dụng wc -mđể đếm số ký tự trên tệp này, kết quả là 7 .

Câu hỏi 1: Nhưng tại sao tôi nhận được 7, tôi không nên lấy " 6 " giả sử rằng nó tính ký tự " cuối dòng "?

Câu hỏi 2: Chính xác thì nó wc -mhoạt động như thế nào?

Câu hỏi 3: Khi tôi sử dụng wc -c(để đếm số byte), tôi có kết quả tương tự wc -m, vậy điểm có hai tùy chọn khác nhau là gì? Họ làm chính xác cùng một công việc, phải không? Nếu không, sự khác biệt và cách làm wc -cviệc?



1
Bạn cũng có thể có 7 nếu tệp đến từ Windows với kết thúc dòng CRLF
Chris H

Câu trả lời:


36

Bạn thực sự chỉ có 6 ký tự ở đó. Hãy thử chạy

cat -A filename

Để xem các ký tự không in của tập tin của bạn. Bạn phải có một cái gì đó thêm. Nếu tôi tạo một tập tin giống như của bạn, tôi thấy

i k k$

Bạn đã đặt một không gian? Điều đó sẽ làm cho 7: i k k $hoặc có thể nó có một dòng mới:

i k k$
$

đó cũng là 7

Như bạn nói

wc -m

đếm nhân vật và

wc -c

đếm byte. Nếu tất cả các ký tự của bạn là một phần của bộ ký tự ASCII, thì sẽ chỉ có 1 byte cho mỗi ký tự, do đó bạn sẽ nhận được cùng một số đếm từ cả hai lệnh.

Thử trên một tệp có ký tự không ASCII:

$ echo ك > testfile
$ wc -m testfile
2 testfile
$ wc -c testfile
3 testfile

Aha! Nhiều byte hơn ký tự bây giờ.


3
Tôi đã sử dụng lệnh " cat -A " và cuối cùng tôi đã thấy rằng tôi có một khoảng trắng trước ký tự " cuối dòng " ( $ ). Đó là lý do tại sao tôi có 7 thay vì 6. Cảm ơn, " con mèo -A " đã giúp đỡ rất nhiều.
SWIIWII

2
@SWIIWII Vâng, tôi vừa thêm nó vào câu trả lời của mình vì tôi nghĩ đó có thể là nó :)
Zanna

1
nhân vật dòng mới được tính là tốt. Ngay cả khi nó không hiển thị, nó vẫn là một ký tự và được tính trong tệp dưới dạng khối dữ liệu. Nhân tiện sử dụng mèo -A. Một lần cũng có thể sử dụng hexdump hoặc xxd để làm điều tương tự
Sergiy Kolodyazhnyy

@Serg có, và cat -Acũng sẽ cho thấy điều đó. Tôi đã thêm vào câu trả lời của mình, cảm ơn :)
Zanna

@SWIIWII đặt mã vào backticks `likethis`để làm cho nó dễ đọc hơn, đừng làm cho nó đậm
phuclv

2
$ locale charmap
UTF-8

Trong môi trường hiện tại của tôi, bộ ký tự là UTF-8, nghĩa là, các ký tự được mã hóa từ 1 đến 4 byte cho mỗi ký tự (mặc dù vì định nghĩa ban đầu của UTF-8 cho phép mã ký tự lên đến 0x7fffffff, hầu hết các công cụ sẽ nhận ra UTF- Chuỗi 8 byte lên đến 6 byte).

Trong bộ ký tự đó, tất cả các ký tự từ Unicode đều có sẵn, a ađược mã hóa thành giá trị byte 65, a là 3 byte 228 185 149 và énhư hai chuỗi 195 169 chẳng hạn.

$ printf 乕 | wc -mc
  1       3
$ printf a | wc -mc
  1       1

Hiện nay:

$ export fr_FR.iso885915@euro
$ locale charmap
ISO-8859-15

Tôi đã sửa đổi môi trường của mình, nơi bộ ký tự hiện là ISO-8859-15 (những thứ khác như ngôn ngữ, ký hiệu tiền tệ, định dạng ngày cũng đã được sửa đổi, bộ sưu tập các cài đặt khu vực đó được gọi là miền địa phương ). Tôi cần bắt đầu một trình giả lập thiết bị đầu cuối mới trong môi trường đó để nó điều chỉnh kết xuất ký tự của nó với miền địa phương mới.

ISO-8859-15 là một bộ ký tự byte đơn, có nghĩa là nó chỉ có 256 ký tự (thực tế thậm chí còn ít hơn số lượng thực sự được bao phủ). Bộ ký tự cụ thể đó được sử dụng cho các ngôn ngữ của Tây Âu vì nó bao gồm hầu hết các ngôn ngữ của nó (và biểu tượng đồng euro).

Nó có aký tự có giá trị byte 65 như trong UTF-8 hoặc ASCII, nó cũng có éký tự (ví dụ như thường được sử dụng trong tiếng Pháp hoặc tiếng Tây Ban Nha) nhưng với giá trị byte 233, nó không có ký tự.

Trong môi trường đó, wc -cwc -msẽ luôn cho kết quả tương tự.

Trong Ubuntu giống như trên hầu hết các hệ thống giống Unix hiện đại, mặc định thường là UTF-8 vì đây là bộ ký tự được hỗ trợ (và mã hóa) duy nhất bao trùm toàn bộ phạm vi Unicode.

Các mã hóa ký tự nhiều byte khác tồn tại, nhưng chúng không được hỗ trợ tốt trên Ubuntu và bạn phải trải qua các vòng để có thể tạo một miền địa phương với chúng, và nếu bạn làm như vậy, bạn sẽ thấy rằng nhiều thứ không làm việc đúng cách

Vì vậy, có hiệu lực trên Ubuntu, các bộ ký tự là một byte hoặc UTF-8.

Bây giờ, một vài ghi chú:

Trong UTF-8, không phải tất cả các chuỗi byte tạo thành các ký tự hợp lệ. Chẳng hạn, tất cả các ký tự UTF-8 không phải là ký tự ASCII được tạo thành với các byte đều có tập bit thứ 8, nhưng chỉ có ký tự đầu tiên có bộ bit thứ 7.

Nếu bạn có một chuỗi byte với tập bit thứ 8, không có chuỗi nào có tập bit thứ 7, thì điều đó không thể được dịch thành ký tự. Và đó là khi bạn bắt đầu gặp vấn đề và không nhất quán vì phần mềm không biết phải làm gì với những điều đó. Ví dụ:

$ printf '\200\200\200' | wc -mc
      0       3
$ printf '\200\200\200' | grep -q . || echo no
no

wcgrepkhông tìm thấy nhân vật nào trong đó nhưng:

$ x=$'\200\200\200' bash -c 'echo "${#x}"'
3

bash tìm thấy 3. Khi nó không thể ánh xạ một chuỗi byte thành một ký tự, nó sẽ xem xét mỗi byte một ký tự.

Nó thậm chí còn phức tạp hơn khi có các điểm mã trong Unicode không hợp lệ dưới dạng ký tự và một số không phải là ký tự và tùy thuộc vào công cụ, mã hóa UTF-8 của chúng có thể hoặc không được coi là ký tự.

Một điều khác cần xem xét là sự khác biệt giữa nhân vật và đồ thị, và cách chúng được hiển thị.

$ printf 'e\u301\u20dd\n'
é⃝
$ printf 'e\u301\u20dd' | wc -mc
      3       6

Ở đó, chúng tôi đã mã 3 ký tự là 6 byte được hiển thị dưới dạng một biểu đồ, bởi vì chúng tôi có 3 ký tự được kết hợp với nhau (một ký tự cơ sở, dấu trọng âm kết hợp và vòng tròn kết hợp).

Việc triển khai GNU wcnhư tìm thấy trên Ubuntu có một -Lcông tắc để cho bạn biết chiều rộng hiển thị của dòng rộng nhất trong đầu vào:

$ printf 'e\u301\u20dd\n' | wc -L
1

Bạn cũng sẽ thấy rằng một số ký tự chiếm 2 ô trong phép tính chiều rộng đó giống như ký tự của chúng ta ở trên:

$ echo 乕 | wc -L
2

Tóm lại: trong từ hoang dã hơn, byte, ký tự và đồ thị không nhất thiết phải giống nhau.


1

Sự khác biệt giữa wc -cwc -mlà trong một miền địa phương có các ký tự đa nhân (giả sử UTF8), trước đây đếm byte, trong khi sau đó đếm các ký tự. Hãy xem xét các tập tin sau:

$ hexdump -C dummy.txt 
00000000  78 79 cf 80 0a                                    |xy...|

(đối với những người không nói UTF8, đó là các chữ cái 'x', 'y' và 'π', theo sau là một dòng mới). Nó dài năm byte:

$ wc -c dummy.txt 
5 dummy.txt

nhưng chỉ có bốn ký tự:

$ wc -m dummy.txt 
4 dummy.txt

Hoặc, xem xét ngay cả UTF-32 trong đó mỗi ký tự có 4 byte.
Jörg W Mittag
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.