Comment puis-je append à nouveau un marqueur d’ordre d’octet Unicode dans Linux?

J’ai un fichier SQL assez volumineux qui commence par le marqueur d’ordre des octets de FFFE. J’ai divisé ce fichier en utilisant l’outil de partage Linux compatible unicode en 100 000 lignes. Mais lorsque vous les renvoyez à Windows, elle n’aime aucune des parties autres que la première, car elle ne contient que le marqueur d’ordre des octets FFFE.

Comment puis-je append ce code à deux octets en utilisant echo (ou toute autre commande bash)?

Quelque chose comme (sauvegarde en premier):

for i in $(ls *.sql) do cp "$i" "$i.temp" printf '\xFF\xFE' > "$i" cat "$i.temp" >> "$i" rm "$i.temp" done 

Basé sur la solution sed de Anonymous , sed -i '1s/^/\xef\xbb\xbf/' foo ajoute la nomenclature au fichier encodé UTF-8 foo . Utile est qu’il convertit également les fichiers ASCII en UTF8 avec BOM

Pour append des nomenclatures à tous les fichiers commençant par “foo-“, vous pouvez utiliser sed . sed a la possibilité de faire une sauvegarde.

 sed -i '1s/^\(\xff\xfe\)\?/\xff\xfe/' foo-* 

Cela montre que sed crée un fichier temporaire avec un nom commençant par “sed”. Si vous savez avec certitude qu’il n’y a pas déjà de nomenclature, vous pouvez simplifier la commande:

 sed -i '1s/^/\xff\xfe/' foo-* 

Assurez-vous que vous devez définir UTF-16, car UTF-8 est différent.

Pour une solution polyvalente quelque chose qui définit la marque d’ordre des octets correcte, que le fichier soit UTF-8, UTF-16 ou UTF-32, j’utiliserais l’option 'bomb' de vim:

 $ 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 signifie s'exécute en mode ex au lieu du mode visuel; -s signifie ne pas imprimer les messages d'état; -c signifie "faire ceci")

Essayez uconv

 uconv --add-signature 

La réponse de Matthew Flaschen est bonne, mais elle comporte quelques défauts.

  • Il n’y a pas de vérification que la copie a réussi avant que le fichier d’origine ne soit tronqué. Il serait préférable de tout faire dépendre d’une copie réussie, ou de tester l’existence du fichier temporaire, ou de fonctionner sur la copie. Si vous êtes une personne de type ceinture et bretelles, vous feriez un combo comme je l’ai illustré ci-dessous
  • Le ls est inutile.
  • J’utiliserais un meilleur nom de variable que “i” – peut-être “fichier”.

Bien sûr, vous pourriez être très paranoïaque et vérifier l’existence du fichier temporaire au début afin de ne pas l’écraser accidentellement et / ou d’utiliser un UUID ou un nom de fichier généré. L’un des mktemp, tempfile ou uuidgen ferait l’affaire.

 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 

Les pièges peuvent être meilleurs que tous les gestionnaires d’erreur que j’ai ajoutés.

Nul doute que cette prudence supplémentaire est exagérée pour un script one-shot, mais ces techniques peuvent vous permettre de gagner du temps, en particulier dans le cadre d’une opération multi-fichiers.

 $ printf '\xEF\xBB\xBF' > bom.txt 

Puis vérifier:

 $ grep -rl $'\xEF\xBB\xBF' . ./bom.txt