Menghapus semua karakter non-ascii dari alur kerja (file)

12

Bagaimana cara saya menghapus semua karakter non-ascii dari satu file? Apakah akan ada perintah khusus untuk melakukan ini?

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

Saya percaya ini menemukan karakter dalam alur kerja, tetapi bagaimana saya akan menghapus semua contoh karakter yang dimaksud?

Mizole Ni
sumber
2
terkait: jika Anda hanya ingin menghindari masalah dengan karakter kontrol (alih-alih menghilangkannya), Anda dapat menggunakannya cat -vuntuk menunjukkannya dalam representasi ASCII untuk mereka. (mis. ^Guntuk \007)
Matija Nalis
1
Ketika Anda mengatakan "karakter non-ascii", apakah Anda juga menyertakan karakter beraksen?
Kapten Man
1
@MatijaNalis Info lebih lanjut tentang representasi: en.wikipedia.org/wiki/Caret_notation
wjandrea
1
Apa gunanya? Sangat sering ada alat khusus atau pendekatan berbeda yang bekerja jauh lebih baik daripada hanya menghapus sekelompok karakter khusus. Harap dicatat bahwa ASCII memang menyertakan beberapa karakter "khusus" seperti tab vertikal, bel, dan NUL - Anda yakin maksud Anda bukan karakter yang dapat dicetak ?
l0b0

Jawaban:

25

Karakter ASCII adalah karakter dalam rentang dari 0 hingga 177 (oktal) secara inklusif .

Untuk menghapus karakter di luar rentang ini dalam file, gunakan

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

The trperintah adalah utilitas yang bekerja pada karakter tunggal , baik mengganti mereka dengan karakter tunggal lainnya (transliterasi), menghapus mereka, atau mengompresi berjalan dari karakter yang sama ke dalam satu karakter.

Perintah di atas akan membaca dari filedan menulis konten yang dimodifikasi newfile. The -dpilihan untuk trmerek utilitas karakter delete (bukan transliterasi mereka), dan -cmembuatnya mempertimbangkan karakter luar interval tertentu (bukan dalam).

LC_ALL=Cmemastikan bahwa setiap nilai byte membentuk karakter yang valid. Tanpa itu, beberapa trimplementasi akan dibatalkan jika mereka menemukan urutan byte yang tidak membentuk karakter yang valid dalam pengkodean karakter lokal.


Untuk mengganti file asli dengan yang dimodifikasi, gunakan

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

Ini mengganti nama file baru dengan nama file lama setelah trselesai dengan sukses. Jika trtidak berhasil diselesaikan, baik karena tidak bisa membaca file asli atau tidak menulis ke file baru, file asli akan dibiarkan tidak berubah.

Atau, untuk mempertahankan sebanyak mungkin meta data (izin dll.) Dari file asli, gunakan

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

Dengan perl

perl -pi -e 's/[^[:ascii:]]//g'
Ishak
sumber
9

Jika yang Anda butuhkan hanyalah sebuah regex: [\x00-\x7F]yang dapat Anda terapkan ke beberapa utilitas:

<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'

Pahami bahwa sed, awk, dan perl mengharapkan "file teks" sebagaimana didefinisikan dalam Unix. Semua berfungsi dengan baik dalam hal ini. Tetapi secara khusus, awk menambahkan baris baru yang tertinggal (apakah ada di file sumber atau tidak) (menggunakan printf menghapus SEMUA baris baru pada input). Tr dirancang untuk bekerja dengan semua jenis file. Namun NUL ( \0) bukan karakter yang valid dalam file teks POSIX dan harus dihindari:

Garis tidak mengandung karakter NUL ...

Bahkan, banyak karakter kontrol akan menghasilkan masalah lain dalam beberapa kondisi tertentu.
Jadi, mungkin Anda perlu[\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'

Kisaran 7-13 (dalam desimal) adalah \a\b\t\n\v\f\r(berurutan).
Kisaran yang serupa (mungkin lebih portabel) dapat ditulis sebagai [^[:space:][:print:]] (similar because it doesn't include\ a \ b` --bell dan backspace--).

<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:]'

Terkait:
Regex setiap
solusi ASCII karakter Perl
File Teks Posix

Ishak
sumber
Perhatikan bahwa input untuk trdapat berupa jenis file apa pun, bukan hanya file teks. awkdi sisi lain, mengambil file teks.
Kusalananda
Sangat sulit bagi saya untuk menemukan hal lain untuk memanggil file "hanya karakter ascii" apa pun selain "file teks" (ya, ya: dalam istilah awam). @ Kusalananda (catatan tentang awk ditambahkan pula).
Isaac
Perhatikan bahwa itu gensub()adalah ekstensi gawk. Anda ingin gsub(...); print, dan menggunakan oktal alih-alih urutan hex (dan LC_ALL = C) menjadi (lebih) portabel.
Stéphane Chazelas
@ StéphaneChazelas Apa batasan sed GNU yang membuat sintaksis GNU spesifik (saya mengerti masalah POSIXLY_CORRECT).
Isaac
[^\o0]adalah untuk mencocokkan karakter selain backslash, o dan 0 di POSIX sed(dalam semua implementasi kecuali GNU sed). Itu bukan batasan GNU sedtetapi ekstensi yang tidak patuh, karena itu dinonaktifkan ketika POSIXLY_CORRECT berada di lingkungan).
Stéphane Chazelas