web-dev-qa-db-fra.com

Comment tester si un fichier utilise CRLF ou LF sans le modifier?

J'ai besoin d'exécuter périodiquement une commande qui garantit que certains fichiers texte sont conservés en mode Linux. Malheureusement dos2unix modifie toujours le fichier, ce qui gâcherait les horodatages du fichier et du dossier et provoquerait des écritures inutiles.

Le script que j'écris est en Bash, donc je préfère les réponses basées sur Bash.

53
Adam Ryczkowski

Vous pouvez utiliser dos2unix en tant que filtre et comparez sa sortie au fichier d'origine:

dos2unix < myfile.txt | cmp - myfile.txt
44
Samuel Edwin Ward

Si l'objectif est simplement d'éviter d'affecter l'horodatage, dos2unix a un -k ou --keepdate option qui gardera le même horodatage. Il devra tout de même faire une écriture pour créer le fichier temporaire et le renommer, mais vos horodatages ne seront pas affectés.

Si une modification du fichier est inacceptable, vous pouvez utiliser la solution suivante de cette réponse .

find . -not -type d -exec file "{}" ";" | grep CRLF
26
j883376

Vous pouvez essayer de grep pour le code CRLF, octal:

grep -U $'\015' myfile.txt

ou hex:

grep -U $'\x0D' myfile.txt
22
don_crissti

Depuis la version 7.1 dos2unix a un -i, --info option pour obtenir des informations sur les sauts de ligne. Vous pouvez utiliser dos2unix lui-même pour tester les fichiers à convertir.

Exemple:

dos2unix -ic *.txt | xargs dos2unix
22
Erwin Waterlander

Première méthode (grep):

Comptez les lignes qui contiennent un retour chariot:

[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos

Comptez les lignes qui se terminent par un retour chariot:

[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos

Celles-ci seront généralement équivalentes; un retour de chariot à l'intérieur d'une ligne (c'est-à-dire pas à la fin) est rare.

Plus efficace:

grep -q $'\r' myfile.txt && echo dos

C'est plus efficace

  1. car il n'a pas besoin de convertir le nombre en une chaîne ASCII, puis de reconvertir cette chaîne en entier et de la comparer à zéro, et
  2. parce que grep -c doit lire l'intégralité du fichier, compter toutes les occurrences du motif, tandis que grep -q peut sortir en voyant la première occurrence du motif.

Remarques:

  • Tout au long de ce qui précède, vous devrez peut-être ajouter le -U option (c'est-à-dire, utilisez -cU ou -qU), car GNU grep devine si le fichier est un fichier texte. S'il pense que le fichier est du texte, il ignore les retours chariot à la fin des lignes, dans un tenter de faire $ dans les expressions régulières fonctionne "correctement" - même si l'expression régulière est \r$! En précisant -U (ou --binary) annule cette conjecture, ce qui oblige grep à traiter le (s) fichier (s) comme binaire et à transmettre les données au mécanisme de correspondance mot pour mot, avec les terminaisons CR intactes.
  • Ne pas faire grep … $'\r\n' myfile.txt, car grep traite \n comme délimiteur de modèle. Tout comme grep -E 'foo|' recherche les lignes contenant foo ou une chaîne nulle, grep $'\r\n' recherche les lignes contenant \r ou une chaîne nulle, et chaque ligne correspond à une chaîne nulle.

Deuxième méthode (file):

[[ $(file myfile.txt) =~ CRLF ]] && echo dos

car file rapporte quelque chose comme:

myfile.txt: UTF-8 Unicode text, with CRLF line terminators

Variante plus sûre:

[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos

  • file -b affiche uniquement le type de fichier et non le nom du fichier. Sans cela, un fichier dont nom inclurait les caractères CRLF déclencherait un faux positif.
  • file - < filename fonctionne même si filename commence par -Voir Script Bash: vérifier si un fichier est un fichier texte .

Attention, la vérification de la sortie de file peut ne pas fonctionner dans un environnement local non anglais.

14
BertS

Utilisation cat -A

$ cat file
hello
hello

Maintenant, si ce fichier a été créé dans des systèmes * NIX, il affichera

$ cat -A file
hello$
hello$

Mais si ce fichier a été créé sous Windows, il affichera

$ cat -A file
hello^M$
hello

^M représente CR et $ représente LF. Notez que Windows n'a pas enregistré la dernière ligne avec CRLF

Cela ne change pas non plus le contenu du fichier.

14
GypsyCosmonaut

une fonction bash pour vous:

# return 0 (true) if first line ends in CR
isDosFile() {
    [[ $(head -1 "$1") == *$'\r' ]]  
}

Ensuite, vous pouvez faire des choses comme

streamFile () {
    if isDosFile /tmp/foo.txt; then
        sed 's/\r$//' "$1"
    else
        cat "$1"
    fi
}

streamFile /tmp/foo.txt | process_lines_without_CR
4
glenn jackman

Si un fichier a des fins de ligne CR-LF de style DOS/Windows, alors si vous le regardez en utilisant un outil basé sur Unix, vous verrez des caractères CR ('\ r') à la fin de chaque ligne.

Cette commande:

grep -l '^M$' filename

affichera filename si le fichier contient une ou plusieurs lignes avec des fins de ligne de style Windows, et n'imprimera rien si ce n'est pas le cas. Sauf que le ^M doit être un caractère de retour chariot littéral, généralement entré dans le terminal en tapant Ctrl+V suivi par Enter (ou Ctrl+V et alors Ctrl+M). Le shell bash vous permet d'écrire un retour chariot littéral comme $'\r' ( documenté ici ), vous pouvez donc écrire:

grep -l $'\r$' filename

D'autres coques peuvent fournir une fonctionnalité similaire.

Vous pouvez utiliser un autre outil à la place:

awk '/\r$/ { exit(1) }' filename

Cela se terminera avec le statut 1 (réglage $? à 1) si le fichier contient des fins de ligne de style Windows et avec un état 0 si ce n'est pas le cas, ce qui le rend utile dans une instruction Shell if (notez l'absence de [ supports ]):

if awk '/\r$/ { exit(1) }' filename ; then
    echo filename has Unix-style line endings
else
    echo filename has at least one Windows-style line ending
fi

Un fichier peut contenir un mélange de fins de ligne de style Unix et de style Windows. Je suppose ici que vous souhaitez détecter les fichiers qui ont des fins de ligne de style Windows .

4
Keith Thompson

Utilisez file:

$ file README.md
README.md: ASCII text, with CRLF line terminators

$ dos2unix README.md
dos2unix: converting file README.md to Unix format...

$ file README.md
README.md: ASCII text
3
Dan Sorak

J'utilise

cat -v filename.txt | diff - filename.txt

qui semble fonctionner. Je trouve la sortie un peu plus facile à lire que

dos2unix < filename.txt | diff - filename.txt

Il est également utile si vous ne pouvez pas installer dos2unix pour certaines raisons.

2
Alex028502