คำสั่งตัวอย่างที่แสดงอาการ: sed 's/./@/' <<<$'\xfc'
ล้มเหลวเนื่องจากไบต์0xfc
ไม่ใช่อักขระ UTF-8 ที่ถูกต้อง
โปรดทราบว่าในทางตรงกันข้ามGNU sed
(Linux แต่ยังสามารถติดตั้งบน macOS) จะส่งไบต์ที่ไม่ถูกต้องผ่านโดยไม่รายงานข้อผิดพลาด
การใช้คำตอบที่ยอมรับก่อนหน้านี้เป็นตัวเลือกหากคุณไม่สนใจที่จะสูญเสียการสนับสนุนสถานที่ที่แท้จริงของคุณ (หากคุณใช้ระบบของสหรัฐอเมริกาและคุณไม่จำเป็นต้องจัดการกับตัวละครต่างประเทศนั่นอาจจะใช้ได้)
อย่างไรก็ตามเอฟเฟกต์เดียวกันสามารถมีad-hocสำหรับคำสั่งเดียวเท่านั้น :
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
หมายเหตุ: สิ่งที่สำคัญคือการที่มีประสิทธิภาพใน LC_CTYPE
การตั้งค่าC
เพื่อLC_CTYPE=C sed ...
จะได้ตามปกตินอกจากนี้ยังมีการทำงาน แต่ถ้าLC_ALL
เกิดขึ้นจะเป็นชุด (อย่างอื่นที่ไม่ใช่C
) ก็จะแทนที่แต่ละLC_*
ตัวแปร -category LC_CTYPE
เช่น LC_ALL
ดังนั้นวิธีการที่มีประสิทธิภาพที่สุดคือการตั้งค่า
อย่างไรก็ตามการตั้งค่า (อย่างมีประสิทธิภาพ) LC_CTYPE
เพื่อใช้กับC
สตริงราวกับว่าแต่ละไบต์เป็นอักขระของตัวเอง ( ไม่มีการตีความตามกฎการเข้ารหัส) โดยไม่คำนึงถึง - การเข้ารหัสแบบหลายไบต์ตามความต้องการ - การเข้ารหัส UTF-8ที่ OS X ใช้โดยค่าเริ่มต้น ที่ตัวละครต่างประเทศมีการเข้ารหัสสัญลักษณ์
สรุป: การตั้งค่าLC_CTYPE
เพื่อC
สาเหตุเปลือกและระบบสาธารณูปโภคที่จะรู้จักตัวอักษรภาษาอังกฤษขั้นพื้นฐานเป็นตัวอักษร (คนที่อยู่ในช่วง ASCII 7 บิต) เพื่อให้ตัวอักษรต่างประเทศ จะไม่ถือว่าเป็นตัวอักษรซึ่งทำให้ตัวอย่างเช่นการแปลงด้านบน / ตัวพิมพ์เล็กล้มเหลว
อีกครั้งนี้อาจจะดีถ้าคุณไม่จำเป็นต้องตรงกับตัวอักษรสัญลักษณ์เข้ารหัสเช่นé
และก็ต้องการที่จะผ่านตัวละครดังกล่าวผ่าน
หากนี่ไม่เพียงพอและ / หรือคุณต้องการเข้าใจสาเหตุของข้อผิดพลาดเดิม (รวมถึงการกำหนดว่าไบต์อินพุตใดที่ทำให้เกิดปัญหา) และทำการแปลงการแปลงตามความต้องการอ่านด้านล่าง
ปัญหาคือการเข้ารหัสไฟล์อินพุตไม่ตรงกับเชลล์
โดยเฉพาะอย่างยิ่งแฟ้มใส่มีอักขระที่เข้ารหัสในทางที่ไม่ถูกต้อง UTF-8 (ตาม @Klas Lindback ที่ระบุไว้ในความคิดเห็น) - นั่นคือสิ่งที่เป็นข้อผิดพลาดคือการพยายามที่จะพูดโดยsed
invalid byte sequence
ส่วนใหญ่แล้วไฟล์อินพุตของคุณใช้การเข้ารหัสไบต์เดียว 8 บิตเช่นที่ISO-8859-1
ใช้บ่อยในการเข้ารหัสภาษา "ยุโรปตะวันตก"
ตัวอย่าง:
ตัวอักษรสำเนียงà
มี Unicode codepoint 0xE0
(224) - ISO-8859-1
เช่นเดียวกับใน อย่างไรก็ตามเนื่องจากธรรมชาติของUTF-8เข้ารหัสนี้ codepoint เดียวจะแสดงเป็น2ไบต์ - 0xC3 0xA0
ในขณะที่พยายามที่จะผ่านbyte เดียว 0xE0
คือไม่ถูกต้องภายใต้ UTF-8
ต่อไปนี้คือการสาธิตปัญหาโดยใช้สตริงที่voilà
เข้ารหัสISO-8859-1
ด้วยโดยà
แสดงเป็นหนึ่งไบต์ (ผ่านสตริงทุบตี ANSI-C- ที่ยกมา ( $'...'
) ที่ใช้\x{e0}
ในการสร้างไบต์):
โปรดทราบว่าsed
คำสั่งนั้นไม่มีประสิทธิภาพในการส่งผ่านอินพุต แต่เราจำเป็นต้องใช้เพื่อกระตุ้นข้อผิดพลาด:
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
หากต้องการเพิกเฉยต่อปัญหาLCTYPE=C
วิธีการข้างต้นสามารถใช้ได้:
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
หากคุณต้องการตรวจสอบว่าส่วนใดของอินพุตที่ทำให้เกิดปัญหาลองทำสิ่งต่อไปนี้:
# Convert bytes in the 8-bit range (high bit set) to hex. representation.
# -> 'voil\x{e0}'
iconv -f ASCII --byte-subst='\x{%02x}' <<<$'voil\x{e0}'
เอาต์พุตจะแสดงไบต์ทั้งหมดที่มีชุดบิตสูง (ไบต์ที่เกินช่วง ASCII 7 บิต) ในรูปแบบเลขฐานสิบหก (อย่างไรก็ตามโปรดทราบว่ายังรวมถึงการเข้ารหัส multibyte UTF-8 ที่เข้ารหัสอย่างถูกต้อง - จำเป็นต้องใช้วิธีการที่ซับซ้อนยิ่งขึ้นในการระบุไบต์ที่ไม่ถูกต้องใน UTF-8 โดยเฉพาะ)
ทำการแปลงการเข้ารหัสตามคำขอ :
ยูทิลิตี้มาตรฐานiconv
สามารถใช้ในการแปลงเป็น ( -t
) และ / หรือจากการ-f
เข้ารหัส( ); iconv -l
แสดงรายการที่รองรับทั้งหมด
ตัวอย่าง:
แปลงจากISO-8859-1
การเข้ารหัสที่มีผลบังคับใช้ในเชลล์ (อิงLC_CTYPE
ซึ่งเป็นUTF-8
เบสโดยค่าเริ่มต้น) อาคารในตัวอย่างข้างต้น:
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
โปรดทราบว่าการแปลงนี้ช่วยให้คุณจับคู่อักขระต่างประเทศได้อย่างถูกต้อง :
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
ในการแปลงอินพุต BACK เป็นISO-8859-1
หลังการประมวลผลเพียงไพพ์ผลลัพธ์ไปยังiconv
คำสั่งอื่น:
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1