Видалення всіх символів, що не відносяться до програми, з робочого процесу (файлу)


13

Як я можу видалити всі символи, які не є ascii, з одного файлу? Чи буде певна команда для виконання цього?

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

Я вважаю, що це знаходить символів у робочому процесі, але як би я видалити всі екземпляри відповідних символів?



2
пов'язано: якщо ви просто хочете уникнути проблем із контрольними характеристиками (замість того, щоб мовчки позбуватися від них), ви можете просто використати їх cat -vдля показу в репрезентації ASCII для них. (напр. ^Gдля \007)
Matija Nalis

1
Коли ви говорите "символи, що не є", ви також включаєте символи з наголосом?
Капітан Людина

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робить утиліту видалення символів (замість транслітерації їх), і -cробить його розглядати символи поза заданого інтервалу (замість внутрішнього).

LC_ALL=Cгарантує, що кожне байтне значення містить дійсний символ. Без нього деякі trреалізації припинять, якби вони знайшли послідовності байтів, які не утворюють дійсних символів в кодуванні символів локалі.


Щоб замінити оригінальний файл модифікованим, використовуйте

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

Він перейменовує новий файл на ім'я старого файлу після trуспішного завершення. Якщо trвін не завершиться успішно, або тому, що він не зміг прочитати оригінальний файл або не записати у новий файл, вихідний файл залишиться незмінним.

Як варіант, щоб зберегти якомога більше метаданих (дозволів тощо) вихідного файлу, використовуйте

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


9

Якщо все, що вам потрібно, це регулярний вираз: [\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 очікують "текстові файли", як визначено в 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з іншого боку, бере текстовий файл.
Кусалаланда

Мені досить важко знайти що-небудь інше, щоб викликати файл "лише ascii символи", що завгодно, але "текстовий файл" (так, так: у простому розумінні). @Kusalananda (примітка про awk додана все одно).
NotAnUnixNazi

Зауважте, що gensub()це розширення gawk. Ви хочете gsub(...); print, і використовуйте восьмерику замість шістнадцяткових послідовностей (і LC_ALL = C), щоб бути (більше) переносними.
Стефан Шазелас

@ StéphaneChazelas Що таке обмеження GNU sed, що робить синтаксис GNU специфічним (я розумію проблему POSIXLY_CORRECT).
NotAnUnixNazi

[^\o0]має відповідати символам, відмінним від зворотної косої, o та 0 у POSIX sed(у всіх реалізаціях, крім sed GNU). Це не обмеження GNU, sedа невідповідне розширення, тому його вимкнено, коли POSIXLY_CORRECT знаходиться в оточенні).
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.