Как я могу повторно добавить маркер порядка байтов Юникода в Linux?
У меня довольно большой файл SQL, который начинается с маркера порядка следования байтов FFFE. Я разделил этот файл с помощью разбивочного инструмента linux с поддержкой Unicode на 100 000 строк. Но при передаче их обратно в окна ему не нравятся никакие другие части, кроме первой, поскольку только на нем есть маркер порядка следования байтов FFFE.
Как я могу добавить этот двухбайтовый код, используя echo (или любую другую команду bash)?
7 ответов
Что-то вроде (бекап первым)):
for i in $(ls *.sql)
do
cp "$i" "$i.temp"
printf '\xFF\xFE' > "$i"
cat "$i.temp" >> "$i"
rm "$i.temp"
done
На основе решения Сед Аноним, sed -i '1s/^/\xef\xbb\xbf/' foo
добавляет спецификацию в кодированный файл UTF-8 foo
, Полезно то, что он также конвертирует файлы ASCII в UTF8 с BOM
Для решения общего назначения, которое устанавливает правильную метку порядка байтов независимо от того, является ли файл UTF-8, UTF-16 или UTF-32, я бы использовал vim 'bomb'
опция:
$ echo 'hello' > foo
$ xxd < foo
0000000: 6865 6c6c 6f0a hello.
$ vim -e -s -c ':set bomb' -c ':wq' foo
$ xxd < foo
0000000: efbb bf68 656c 6c6f 0a ...hello.
(-e
значит работает в режиме ex вместо визуального режима; -s
означает не печатать сообщения о состоянии; -c
значит "сделай это")
Чтобы добавить спецификации ко всем файлам, начинающимся с "foo-", вы можете использовать sed
, sed
имеет возможность сделать резервную копию.
sed -i '1s/^\(\xff\xfe\)\?/\xff\xfe/' foo-*
strace
В этом примере sed создает временный файл с именем, начинающимся с "sed". Если вы точно знаете, что спецификации уже нет, вы можете упростить команду:
sed -i '1s/^/\xff\xfe/' foo-*
Убедитесь, что вам нужно установить UTF-16, потому что то есть UTF-8 отличается.
Ответ Мэтью Флешена хороший, однако у него есть пара недостатков.
- Нет проверки, что копирование прошло успешно, прежде чем исходный файл будет обрезан. Было бы лучше сделать все зависящее от успешной копии, либо проверить наличие временного файла, либо работать с этой копией. Если вы человек с поясом и подтяжками, вы бы сделали комбо, как я показал ниже
ls
не нужно- Я бы использовал лучшее имя переменной, чем "i" - возможно, "file".
Конечно, вы можете быть очень параноиком и проверять наличие временного файла в начале, чтобы вы случайно не перезаписали его и / или не использовали UUID или сгенерированное имя файла. Один из mktemp, tempfile или uuidgen сделает свое дело.
td=TMPDIR
export TMPDIR=
usertemp=~/temp # set this to use a temp directory on the same filesystem
# you could use ./temp to ensure that it's one the same one
# you can use mktemp -d to create the dir instead of mkdir
if [[ ! -d $usertemp ]] # if this user temp directory doesn't exist
then # then create it, unless you can't
mkdir $usertemp || export TMPDIR=$td # if you can't create it and TMPDIR is/was
fi # empty then mktemp automatically falls
# back to /tmp
for file in *.sql
do
# TMPDIR if set overrides the argument to -p
temp=$(mktemp -p $usertemp) || { echo "$0: Unable to create temp file."; exit 1; }
{ printf '\xFF\xFE' > "$temp" &&
cat "$file" >> "$temp"; } || { echo "$0: Write failed on $file"; exit 1; }
{ rm "$file" &&
mv "$temp" "$file"; } || { echo "$0: Replacement failed for $file; exit 1; }
done
export TMPDIR=$td
Ловушки могут быть лучше, чем все отдельные обработчики ошибок, которые я добавил.
Без сомнения, все эти дополнительные меры предосторожности являются чрезмерным для сценария с одним выстрелом, но эти методы могут спасти вас, когда наступит пуш, особенно в многофайловой операции.
$ printf '\xEF\xBB\xBF' > bom.txt
Затем проверьте:
$ grep -rl $'\xEF\xBB\xBF' .
./bom.txt