J'essaie d'écrire un script qui supprimera automatiquement les nomenclatures UTF-8 d'un fichier. Je ne parviens pas à détecter si le fichier en a un ou non. Voici mon code:
function has-bom {
# Test if the file starts with 0xEF, 0xBB, and 0xBF
head -c 3 "$1" | grep -P '\xef\xbb\xbf'
return $?
}
Pour une raison quelconque, head
semble ignorer la nomenclature devant le fichier. Par exemple, en exécutant cette
printf '\xef\xbb\xbf' > file
head -c 3 file
n'imprimera rien.
J'ai essayé de rechercher une option dans head --help
qui me permettrait de contourner ce problème, mais sans succès. Y a-t-il quelque chose que je puisse faire pour que cela fonctionne?
Commençons par démontrer que head
fonctionne réellement correctement:
$ printf '\xef\xbb\xbf' >file
$ head -c 3 file
$ head -c 3 file | hexdump -C
00000000 ef bb bf |...|
00000003
Créons à présent une fonction has_bom
. Si votre grep
supporte -P
, une option est:
$ has_bom() { head -c3 "$1" | LC_ALL=C grep -qP '\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
Actuellement, seul GNU grep
prend en charge -P
.
Une autre option consiste à utiliser le $'...'
de bash:
$ has_bom() { head -c3 "$1" | grep -q $'\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
ksh
et zsh
prennent également en charge $'...'
, mais cette construction n'est pas POSIX et dash
ne la prend pas en charge.
Remarques:
L'utilisation d'un return $?
explicite est facultative. La fonction retournera par défaut avec le code de sortie de la dernière commande exécutée.
J'ai utilisé le formulaire POSIX pour définir des fonctions. Cela équivaut à la forme bash mais vous pose un problème en moins si vous devez exécuter la fonction sous un autre shell.
bash accepte l'utilisation du caractère -
dans un nom de fonction, mais il s'agit d'une fonctionnalité controversée. Je l'ai remplacé par _
qui est plus largement accepté. (Pour plus d'informations sur cette question, voir cette réponse .)
L'option -q
de grep
le rend silencieux, ce qui signifie qu'il définit toujours un code de sortie correct, mais n'envoie aucun caractère à stdout.
J'ai appliqué ce qui suit pour la première ligne de lecture:
read c
if (( "$(printf "%d" "'${c:0:1}")" == 65279 )) ; then c="${c:1}" ; fi
Cela supprime simplement la nomenclature de la variable.