Мне нужно заменить некоторые непечатаемые символы пробелами в файле.
В частности, все символы от 0x00
до 0x1F
, кроме 0x09
(TAB), 0x0A
(новая строка), 0x0D
(CR)
До сих пор мне просто нужно было заменить 0x00
персонажа. Поскольку моя предыдущая ОС была AIX (без команд GNU), я не могу использовать sed
(ну, я могу, но у нее были некоторые ограничения). Итак, я нашел следующую команду с помощью perl
, которая работала как ожидалось:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Сейчас я работаю над Linux, поэтому я ожидал, что смогу использовать sed
команду.
Мои вопросы:
Подходит ли эта команда для замены этих символов? Я пытался, и это похоже на работу, но я хочу убедиться:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Я думал
perl -p
работает какsed
. Итак, почему предыдущая команда работает (по крайней мере, она не дает сбоя), а следующая нет?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Это говорит мне:
sed: -e выражение # 1, символ 34: недопустимый символ сопоставления
perl -p
печатает конечный продуктstdin
после выполнения необходимых операций, в данном случае это просто замена.sed
регулярное выражение может отличаться отperl
.Ответы:
Это типичная работа для
tr
:В вашем случае это не работает,
sed
потому что вы находитесь в локали, где эти диапазоны не имеют смысла. Если вы хотите работать с байтовых значений в отличие от персонажей и где порядок основан на численном значении этих байтов, лучше всего, чтобы использовать C локали . Ваш код работал бы сLC_ALL=C
GNUsed
, но использованиеsed
(не говоря уже оperl
) - это немного излишне (и\xXX
они не переносимы междуsed
реализациями, хотя этотtr
подход - POSIX).Вы также можете доверять представлению вашей локали о том, что означают печатные символы:
Но с GNU
tr
(как это обычно бывает в системах на основе Linux) это работает только в локалях, где символы являются однобайтовыми (как правило, не в UTF-8).В локали C это также исключает DEL (0x7f) и все байтовые значения выше (не в ASCII).
В локалях UTF-8 вы можете использовать GNU, в
sed
которой нет проблем с GNUtr
:(заметим , что те
\r
,\t
не являются стандартными, и ГНУsed
не распознает их , еслиPOSIXLY_CORRECT
в окружающей среде (будет рассматривать их как обратную косую черту, г и т быть частью набора , как требует POSIX)).Это не будет преобразовывать байты, которые не формируют допустимые символы, если таковые имеются.
источник
tr
делает команда. Я понимаю (более или менее), чтоLC_ALL = C
есть, но не все вместе. Тем не менееtr -d
удаляет эти символы, но я хочу заменить пробелами. Извините, название было неправильным. Я только что понял, когда @don_crissti изменился.XCOM
. Например, не ASCII-символы, такие какÉ
, кодируются (используютod -xa
) как0xC9
, так что я думаю, что это будетISO-8859-1
.locale -a
чтобы увидеть, есть ли локали с iso8859-1 в качестве кодировки в вашей системе и использоватьLC_CTYPE=<that-locale> tr ...[:print:]...
для конвертации непечатаемых в этой локали. Или вы можете использовать iconv для преобразования этих файлов в кодировку вашей локали.LC_ALL=en_US.iso88591
. Таким образом, ваша команда (tr -c '[:print:]\t\r\n' '[ *]'
) прекрасно работает без изменения локали или преобразования файла. Большое спасибо.Я пытался отправить уведомление через libnotify с содержимым, которое может содержать непечатные символы. Существующие решения для меня не совсем работали (использование белого списка символов с использованием
tr
работ, но с удалением любых многобайтовых символов).Вот что сработало при прохождении теста::
источник