การลบอักขระที่ไม่ใช่แบบ ASCII ทั้งหมดออกจากเวิร์กโฟลว์ (ไฟล์)


13

ฉันจะลบอักขระที่ไม่ใช่ ASCII ทั้งหมดออกจากไฟล์เดียวได้อย่างไร จะมีคำสั่งเฉพาะให้ทำสิ่งนี้หรือไม่?

grep --colour='auto' -P -n'[^\x00-\x7]' /usr/local/...

ฉันเชื่อว่าสิ่งนี้จะค้นหาอักขระภายในเวิร์กโฟลว์ แต่ฉันจะลบอินสแตนซ์ทั้งหมดของอักขระที่สงสัยได้อย่างไร



2
ที่เกี่ยวข้อง: หากคุณเพียงต้องการหลีกเลี่ยงปัญหาเกี่ยวกับตัวควบคุม (แทนที่จะกำจัดอย่างเงียบ ๆ ) คุณสามารถใช้cat -vเพื่อแสดงพวกเขาใน ASCII represantation สำหรับพวกเขา (เช่น^Gสำหรับ\007)
Matija Nalis

1
เมื่อคุณพูดว่า "อักขระที่ไม่ใช่ ASCII" คุณรวมอักขระที่เน้นเสียงหรือไม่
Captain Man

1
@MatijaNalis ข้อมูลเพิ่มเติมเกี่ยวกับการเป็นตัวแทน: en.wikipedia.org/wiki/Caret_notation
wjandrea

1
กรณีการใช้งานคืออะไร? บ่อยครั้งที่มีเครื่องมือเฉพาะหรือวิธีการต่าง ๆ ที่ทำงานได้ดีกว่าเพียงแค่ลบอักขระพิเศษจำนวนมาก โปรดทราบว่า ASCII มีอักขระ "พิเศษ" หลายตัวเช่นแท็บแนวตั้งเบลล์และ NUL - คุณแน่ใจหรือว่าคุณไม่ได้หมายถึงตัวอักษรที่พิมพ์ได้ ?
l0b0

คำตอบ:


26

อักขระ ASCII เป็นตัวละครในช่วง 0-177 (ฐานแปด) อย่างครอบคลุม

หากต้องการลบอักขระนอกช่วงนี้ในไฟล์ให้ใช้

LC_ALL=C tr -dc '\0-\177' <file >newfile

trคำสั่งเป็นโปรแกรมที่ทำงานบนตัวอักษรเดียวทั้งทำหน้าที่แทนพวกเขากับตัวละครอื่น ๆ เดียว (ทับศัพท์) ลบพวกเขาหรือการบีบอัดวิ่งของตัวละครเดียวกันในตัวเดียว

คำสั่งด้านบนจะอ่านfileและเขียนเนื้อหาที่แก้ไขไปnewfileแล้ว -dตัวเลือกที่จะtrทำให้ยูทิลิตี้ตัวอักษรลบ (แทน transliterating พวกเขา) และ-cทำให้พิจารณาตัวละครนอกช่วงเวลาที่กำหนด (แทนภายใน)

LC_ALL=Cทำให้แน่ใจว่าทุกค่าไบต์ประกอบด้วยอักขระที่ถูกต้อง หากไม่มีมันtrการใช้งานบางอย่างจะยกเลิกหากพวกเขาพบลำดับของไบต์ที่ไม่ได้สร้างตัวละครที่ถูกต้องในการเข้ารหัสอักขระของสถานที่


ในการแทนที่ไฟล์ต้นฉบับด้วยไฟล์ที่แก้ไขให้ใช้

LC_ALL=C tr -dc '\0-\177' <file >newfile &&
mv newfile file

การเปลี่ยนชื่อไฟล์ใหม่เป็นชื่อของไฟล์เก่าหลังจากtrเสร็จสมบูรณ์ หากtrไม่เสร็จสมบูรณ์อาจเป็นเพราะไม่สามารถอ่านไฟล์ต้นฉบับหรือเขียนไปยังไฟล์ใหม่ไฟล์ต้นฉบับจะไม่เปลี่ยนแปลง

อีกวิธีหนึ่งคือการใช้ meta data (การอนุญาต ฯลฯ ) ของไฟล์ต้นฉบับให้มากที่สุด

cp file tmpfile &&
LC_ALL=C tr -dc '\0-\177' <tmpfile >file &&
rm tmpfile


9

หากสิ่งที่คุณต้องการคือ regex: [\x00-\x7F]คุณสามารถนำไปใช้กับระบบสาธารณูปโภคต่าง ๆ ได้:

<file LC_ALL=C   sed   's/[^\o0-\o177]//g'      # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\177]/,"");print}'
<file            perl  -pe 's/[^[:ascii:]]//g;'
<file LC_ALL=C   tr    -dc '\0-\177'

เข้าใจว่า sed, awk และ perl คาดหวังว่า "text files" ตามที่กำหนดไว้ใน Unix ทำงานได้ดีในกรณีนี้ แต่โดยเฉพาะ awk เพิ่มบรรทัดใหม่ต่อท้าย (ไม่ว่าจะมีอยู่ในไฟล์ต้นฉบับหรือไม่) (การใช้ printf จะลบบรรทัดใหม่ทั้งหมดในอินพุต) tr ถูกออกแบบมาให้ทำงานกับไฟล์ประเภทใดก็ได้ อย่างไรก็ตาม NUL ( \0) ไม่ใช่อักขระที่ถูกต้องในไฟล์ข้อความ POSIXและควรหลีกเลี่ยง:

บรรทัดไม่มีอักขระ NUL ...

ในความเป็นจริงอักขระควบคุมจำนวนมากจะสร้างปัญหาอื่น ๆ ภายใต้เงื่อนไขเฉพาะบางอย่าง
ดังนั้นคุณอาจต้องการ[\x07-\x0d\x20-\x7e]

<file LC_ALL=C   sed   's/[^\o007-\o015\o040-\o176]//g'            # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\15\40-\176]/,"");print}'
<file            perl  -pe 's/[^\x{7}-\x{d}\x{20}-\x{7e}]//g;'
<file LC_ALL=C   tr    -dc '\7-\15\40-\176'

ช่วง 7-13 (เป็นทศนิยม) คือ\a\b\t\n\v\f\r(ตามลำดับ)
ช่วงที่คล้ายกัน (อาจพกพามากกว่า) อาจเขียนเป็น[^[:space:][:print:]] (similar because it doesn't include\ a \ b` - เบลล์และแบ็กสเปซ -)

<file LC_ALL=C   sed   's/[^[:space:][:print:]]//g'  # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^[:space:][:print:]]/,"");print}'
<file            perl   -pe 's/[^[:space:][:print:]]//g;'
<file LC_ALL=C   tr     -dc '[:space:][:print:]'

ที่เกี่ยวข้อง:
Regex ใด ๆ ตัวอักษร ASCII
โซลูชั่น Perl
ไฟล์ข้อความ Posix


โปรดทราบว่าการป้อนข้อมูลtrสามารถเป็นไฟล์ประเภทใดก็ได้ไม่ใช่แค่ไฟล์ข้อความ awkในขณะที่ใช้ไฟล์ข้อความ
Kusalananda

มันค่อนข้างยากสำหรับฉันที่จะหาสิ่งอื่นเพื่อเรียกไฟล์ "only ascii characters" อะไรก็ได้ แต่เป็น "text file" (ใช่, ใช่: ในเงื่อนไขของคนธรรมดา) @Kusalananda (หมายเหตุเกี่ยวกับ awk เพิ่มอยู่แล้ว)
NotAnUnixNazi

โปรดทราบว่าgensub()เป็นส่วนขยายเพ่งพิศ คุณต้องการgsub(...); printและใช้เลขฐานแปดแทนลำดับเลขฐานสิบหก (และ LC_ALL = C) เพื่อเป็นแบบพกพา (เพิ่มเติม)
Stéphane Chazelas

@ StéphaneChazelasข้อ จำกัด ของ GNU sed ที่ทำให้ไวยากรณ์ของ GNU นั้นเฉพาะเจาะจงคืออะไร (ฉันเข้าใจปัญหา POSIXLY_CORRECT)
NotAnUnixNazi

[^\o0]คือการจับคู่กับอักขระอื่นที่ไม่ใช่แบ็กสแลช, o และ 0 ใน POSIX sed(ในการนำไปใช้ทั้งหมดยกเว้น GNU sed) นั่นไม่ใช่ข้อ จำกัดของ GNU sedแต่เป็นส่วนขยายที่ไม่เข้ากันซึ่งเป็นเหตุผลว่าทำไมจึงปิดใช้งานเมื่อ POSIXLY_CORRECT อยู่ในสภาพแวดล้อม)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.