คำสั่ง“ wc -c” และ“ wc -m” ใน linux


24

ฉันมีไฟล์ข้อความเนื้อหาของมันคือ:

i k k

เมื่อฉันใช้wc -mในการนับจำนวนตัวอักษรบนไฟล์นี้ผลที่ได้คือ7

คำถามที่ 1: แต่ทำไมฉันถึงได้ 7 ฉันไม่ควรได้ " 6 " ถ้าคิดว่านับตัวอักษร" end-of-line "?

คำถามที่ 2: wc -mทำงานอย่างไร

คำถามที่ 3: ตอนที่ผมใช้wc -c(การนับจำนวนไบต์) ผมมีผลเช่นเดียวกับwc -mดังนั้นสิ่งที่เป็นจุดของการมีสองตัวเลือกที่แตกต่างกัน ? พวกเขาทำงานอย่างเดียวกันใช่มั้ย ถ้าไม่แตกต่างกันและwc -cทำงานอย่างไร



1
นอกจากนี้คุณยังจะได้มี 7 ถ้าคุณไฟล์มาจาก Windows ด้วย CRLF ปลายสาย
คริส H

คำตอบ:


36

คุณควรมีเพียง 6 ตัวอักษรแน่นอน ลองวิ่ง

cat -A filename

หากต้องการดูตัวอักษรที่ไม่ได้พิมพ์ในไฟล์ของคุณ คุณต้องมีอะไรเป็นพิเศษ ถ้าฉันทำไฟล์เหมือนของคุณฉันเห็น

i k k$

คุณใส่ที่ว่างหรือไม่? ที่จะทำให้ 7: i k k $หรืออาจจะมีการขึ้นบรรทัดใหม่:

i k k$
$

ซึ่งก็คือ 7

ตามที่คุณพูด

wc -m

นับจำนวนตัวอักษรและ

wc -c

นับไบต์ หากอักขระทั้งหมดของคุณเป็นส่วนหนึ่งของชุดอักขระ ASCII จะมีเพียง 1 ไบต์ต่ออักขระดังนั้นคุณจะได้รับจำนวนเดียวกันจากคำสั่งทั้งสอง

ลองไฟล์ที่ไม่มีตัวอักษร ASCII:

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

Aha! จำนวนไบต์มากกว่าตัวอักษรตอนนี้


3
ฉันใช้คำสั่ง" cat -A " และในที่สุดฉันก็พบว่ามีช่องว่างหนึ่งช่องก่อนอักขระ" end-of-line " ( $ ) นั่นเป็นเหตุผลที่ฉันได้ 7 แทน 6 ขอบคุณ " cat -A " ช่วยได้มาก
SWIIWII

2
@SWIIWII ใช่ฉันเพียงแค่เสริมว่าคำตอบของฉันเป็นฉันคิดว่าอาจจะเป็นมัน :)
Zanna

1
อักขระบรรทัดใหม่ถูกนับเช่นกัน แม้ว่ามันจะมองไม่เห็น แต่มันก็ยังคงเป็นตัวละครและนับเป็นไฟล์ข้อมูล ใช้แมวได้ดี - ครั้งหนึ่งยังสามารถใช้ hexdump หรือ xxd เพื่อทำสิ่งเดียวกัน
Sergiy Kolodyazhnyy

@Serg ใช่แล้วและcat -Aจะแสดงให้เห็นเช่นกัน ฉันเพิ่มลงในคำตอบของฉันขอบคุณ :)
Zanna

@SWIIWII รหัสใส่ใน backticks `likethis`ที่จะทำให้มันอ่านไม่ได้ทำให้มันหนา
phuclv

2
$ locale charmap
UTF-8

ในสภาพแวดล้อมปัจจุบันของฉันชุดอักขระคือ UTF-8 นั่นคืออักขระถูกเข้ารหัสด้วย 1 ถึง 4 ไบต์ต่ออักขระ (แม้ว่าเนื่องจากนิยามดั้งเดิมของ UTF-8 อนุญาตให้ใช้รหัสอักขระได้ถึง 0x7fffffff เครื่องมือส่วนใหญ่จะรู้จัก UTF- ลำดับ 8 ไบต์สูงสุด 6 ไบต์)

ในชุดอักขระนั้นอักขระทั้งหมดจาก Unicode จะพร้อมใช้งาน a aจะถูกเข้ารหัสเป็นค่าไบต์ 65 เป็น 3 ไบต์ 228 185 149 และéเป็นลำดับสองไบต์ 195 169 เป็นต้น

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

ขณะนี้:

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

ฉันได้มีการปรับเปลี่ยนสภาพแวดล้อมของฉันที่ชุดอักขระในขณะนี้คือ ISO-8859-15 (สิ่งอื่น ๆ เช่นภาษาสัญลักษณ์สกุลเงินรูปแบบวันนอกจากนี้ยังได้รับการแก้ไขคอลเลกชันของการตั้งค่าภูมิภาคเหล่านั้นถูกเรียกว่าเป็นสถานที่เกิดเหตุ ) ฉันต้องเริ่มต้นเทอร์มินัลอีมูเลเตอร์ใหม่ในสภาพแวดล้อมนั้นเพื่อปรับการแสดงผลตัวละครให้เข้ากับสถานที่ใหม่

ISO-8859-15 เป็นชุดอักขระไบต์เดียวซึ่งหมายความว่ามีเพียง 256 อักขระ (จริง ๆ แล้วยังน้อยกว่าที่ครอบคลุมจริง) ชุดอักขระเฉพาะนั้นใช้สำหรับภาษาของยุโรปตะวันตกเนื่องจากครอบคลุมภาษาส่วนใหญ่ (และสัญลักษณ์ยูโร)

มันมีaตัวอักษรที่มีค่าไบต์ 65 เช่นใน UTF-8 หรือ ASCII มันยังมีéตัวละคร (เช่นที่ใช้กันทั่วไปในฝรั่งเศสหรือสเปนเป็นต้น) แต่ด้วยค่าไบต์ 233 มันไม่มีตัวอักษร乕

ในสภาพแวดล้อมนั้นwc -cและwc -mจะให้ผลลัพธ์เดียวกันเสมอ

ใน Ubuntu เหมือนกับระบบ Unix ที่ทันสมัยที่สุดค่าเริ่มต้นมักจะเป็น UTF-8 เนื่องจากเป็นชุดอักขระ (และการเข้ารหัส) ที่รองรับเท่านั้นที่ครอบคลุมช่วง Unicode ทั้งหมด

มีการเข้ารหัสตัวอักษรแบบหลายไบต์อื่น ๆ แต่มันก็ไม่ได้รับการสนับสนุนอย่างดีบน Ubuntu และคุณต้องผ่านการวนซ้ำเพื่อให้สามารถสร้างสถานที่กับสิ่งเหล่านั้นได้และถ้าคุณทำคุณจะพบว่าหลายสิ่งไม่ ทำงานอย่างถูกต้อง

ดังนั้นเมื่อใช้กับ Ubuntu ชุดอักขระจะเป็นไบต์เดียวหรือ UTF-8

ตอนนี้อีกไม่กี่หมายเหตุ:

ใน UTF-8 ไม่ใช่ลำดับไบต์ทั้งหมดที่มีอักขระที่ถูกต้อง ตัวอย่างเช่นตัวอักษร UTF-8 ทั้งหมดที่ไม่ใช่ ASCII จะถูกสร้างขึ้นด้วยไบต์ที่ทุกคนมีชุดบิตที่ 8 แต่มีเพียงชุดแรกเท่านั้นที่มีชุดบิตที่ 7

หากคุณมีลำดับไบต์ที่มีการตั้งค่าบิตที่ 8 ซึ่งไม่มีการตั้งค่าบิตที่ 7 จากนั้นไม่สามารถแปลเป็นอักขระ และเมื่อคุณเริ่มมีปัญหาและความไม่สอดคล้องเนื่องจากซอฟต์แวร์ไม่รู้ว่าจะทำอย่างไรกับสิ่งเหล่านั้น ตัวอย่างเช่น

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

wcและgrepพบว่าไม่มีตัวละครในนั้น แต่:

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

bash พบ 3. เมื่อไม่สามารถแม็พลำดับของไบต์กับอักขระมันจะพิจารณาอักขระแต่ละไบต์

มันอาจมีความซับซ้อนมากขึ้นเนื่องจากมี codepoints ใน Unicode ที่ไม่ถูกต้องเป็นตัวอักษรและบางตัวที่ไม่ใช่ตัวอักษรและขึ้นอยู่กับเครื่องมือการเข้ารหัส UTF-8 อาจขึ้นอยู่กับว่าเป็นตัวอักษรหรือไม่

สิ่งที่ควรคำนึงถึงอีกประการหนึ่งคือความแตกต่างระหว่างตัวละครกับกราฟและวิธีการแสดงผล

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

ที่นั่นเรามีรหัส 3 ตัวอักษรเป็น 6 ไบต์ที่แสดงเป็นหนึ่งกราฟเพราะเรามี 3 ตัวอักษรรวมกัน (ตัวละครฐานหนึ่งการรวมกันของสำเนียงเฉียบพลันและวงกลมล้อมรอบการรวมกัน)

การนำ GNU ไปใช้wcตามที่พบในอูบุนตูมี-Lสวิตช์เพื่อบอกความกว้างในการแสดงผลของบรรทัดที่กว้างที่สุดในอินพุต:

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

คุณจะพบว่าตัวละครบางตัวใช้ 2 เซลล์ในการคำนวณความกว้างเช่นเดียวกับตัวละครของเราจากด้านบน:

$ echo 乕 | wc -L
2

โดยสรุป: ในคำ wilder, ไบต์, ตัวละครและกราฟไม่จำเป็นต้องเหมือนกัน


1

ความแตกต่างระหว่างwc -cและwc -mคือในโลแคลที่มีอักขระหลายไบต์ (เช่น UTF8) ซึ่งเป็นอดีตนับไบต์ในขณะที่หลังนับอักขระ พิจารณาไฟล์ต่อไปนี้:

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

(สำหรับผู้ที่ไม่พูด UTF8 นั่นคือตัวอักษร 'x', 'y' และ 'π' ตามด้วยบรรทัดใหม่) ยาวห้าไบต์:

$ wc -c dummy.txt 
5 dummy.txt

แต่มีความยาวเพียงสี่ตัวอักษร:

$ wc -m dummy.txt 
4 dummy.txt

หรือพิจารณาแม้แต่ UTF-32 โดยที่ตัวละครทุกตัวมีขนาด 4 ไบต์
Jörg W Mittag
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.