У меня есть файл, который был создан путем копирования содержимого из документа DOCX с помощью LibreOffice в текстовый файл. Я изменил файл с sed
, чтобы удалить дополнительные пробелы и другие вещи, но затем я заметил пространство, которое было неуязвимо для обычной команды:
sed -r 's:some-text :some-text:g' -i file
После использования cat -A file
я обнаружил, что это выглядит так:
<p>M-BM- Lorem ipsum</p>
Как это убрать?
Попробовав много вещей, я наконец нашел решение. Чтобы заменить этот странный символ на sed, вам нужно скопировать и вставить точный текст, который содержит это странное пространство рядом с ним, а затем вставить его непосредственно в команду sed:
sed -r 's:paste-here:<p>:g' -i file
Выглядите так в команде sed:
sed -r 's:<p> :<p>:g' -i file
, но все равно будет работать.
M-BM-
символы являются представлением ASCII последовательности байта 0xc2 0xa0
, который является кодированием UTF8 unicode символа A0
- неразрывный пробел. Этот символ может быть вставлен и в LibreOffice и в документы Microsoft Word с помощью сочетания клавиш Ctrl+Shift+SPACE.
Например, если мы создаем новый .odt документ в LibreOffice и вводим ABCCtrl+Shift+SPACEDEF, затем Save As... Text
(игнорирование предупреждения, что документ может содержать функции, которые не могут быть сохранены в том формате), затем просмотрите получающийся .txt файл с cat
:
$ cat nbsp.txt
ABC DEF
и с другой стороны с -v
переключитесь для показа непечатаемых символов
$ cat -v nbsp.txt
M-oM-;M-?ABCM-BM- DEF
Обратите внимание, что мы также получаем начальную последовательность M-oM-;M-?
или шестнадцатеричный 0xef 0xbb 0xbf
который является меткой порядка байтов (BOM) UTF8, согласовывающейся с типом файла, о котором сообщают file
команда т.е.
$ file nbsp.txt
nbsp.txt: UTF-8 Unicode (with BOM) text
Используя od
для печати шестнадцатеричных значений в порядке байтов, мы видим
$ od -tx1 nbsp.txt
0000000 ef bb bf 41 42 43 c2 a0 44 45 46 0a
0000014
Возможно управлять этими символами с помощью стандартных инструментов как sed
или tr
путем определения шестнадцатеричного числа кодирует как escape-последовательности, например, заменять неразрывное пространство плоскостью пространство ASCII
$ sed 's/\xc2\xa0/ /g' nbsp.txt
ABC DEF
Проверка снова с od
подтверждает, что замена обычным ASCII располагает 0x20 с интервалами (десятичные 32)
$ sed 's/\xc2\xa0/ /g' nbsp.txt | od -tx1
0000000 ef bb bf 41 42 43 20 44 45 46 0a
0000013
В терминале гнома (и возможно другие UTF8-осведомленные эмуляторы терминала), также возможно ввести unicode значение кодовой точки непосредственно с помощью сочетания клавиш Ctrl+Shift+u, сопровождаемый шестнадцатеричным значением затем клавиша Enter - последовательность обнаруживается первоначально как u ̲. ̲. ̲. ̲, но затем символ должен сочинить, когда Вы совершаете нападки, Входят, например, для той же неразрывной замены пространства мы можем сделать
$ sed 's/Ctrl+Shift+ua0
который отображается как
$ sed 's/̲/̲u̲a̲0̲
и затем завершается как
$ sed 's/ / /g' nbsp.txt
ABC DEF
Используя cat -v
мы можем подтвердить M-BM-
последовательность стала обычным пространством
$ sed 's/ / /g' nbsp.txt | cat -v
M-oM-;M-?ABC DEF
Можно хотеть посмотреть на большее количество универсальных преобразователей кодирования, таких как iconv и uconv также.
Вы можете удалить ^ M из файлов напрямую с помощью команды sed, например, :
sed -i'.bak' s/\r//g *.*
Если изменения вас устраивают, удалите файлы .bak:
rm -v *.bak
«cat -v file» покажет непечатаемые символы в файле. Просто перенаправьте вывод во временный файл и используйте vim для замены символов M-BM ничем.
% s / M-BM- // g
Самое простое решение.
Небольшой скрипт для удаления этого дьявола M-BM-персонажа! ;) На всякий случай помогут любые люди.
#!/bin/bash
#############################################################################
# SCRIPT: M-BM-Remover.sh
# DESCRIPTION:
# This script will be able to detect hidden caracter "M-BM-",
# And/Or remove this !
# REVISIONS:
# 2014/06/11 YG
#____________________________________________________________________________
#
# PARAMETERS:
# > $1 :TARGET, (e.g. '"*.sh"' )
# > $2 :ACTION, (e.g. 'remove' )
# > $2 :BACKUP, (e.g. '' )
#
#############################################################################
TARGET=$1
ACTION=$2
BACKUP=$3
if [ "$TARGET" = "" ]
then
echo 'Need to choose target file'
echo 'M-BM-Remover [TARGET] [show/remove] [backup]'
echo 'Example : M-BM-Remover "*.sh" remove backup'
exit
fi
echo "ACTION = $ACTION";
echo "TARGET = $TARGET";
echo
if [ "$ACTION" = "show" ]
then
for file in $TARGET
do
if [ "$file" != "M-BM-Remover.sh" ]
then
echo "Traitement de $file ..."
cat -v $file | grep M-BM-
NB=`cat -v $file | grep M-BM- | wc -l`
echo "Occurence(s) : $NB"
fi
done
fi
if [ "$ACTION" = "remove" ] || [ "$ACTION" = "" ]
then
for file in $TARGET
do
if [ "$file" != "M-BM-Remover.sh" ]
then
echo "Traitement de $file ..."
NB=`cat -v $file | grep M-BM- | wc -l`
if [ "$BACKUP" = "backup" ]
then
cat $file > $file.bak
fi
cat -v $file.bak | sed s/M-BM-//g > $file
echo "Occurence(s) removed : $NB"
fi
echo
done
fi