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.
Vous pouvez utiliser dos2unix
en tant que filtre et comparez sa sortie au fichier d'origine:
dos2unix < myfile.txt | cmp - myfile.txt
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
Vous pouvez essayer de grep
pour le code CRLF, octal:
grep -U $'\015' myfile.txt
ou hex:
grep -U $'\x0D' myfile.txt
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
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
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:
-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.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.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
où
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.
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.
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
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 .
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
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.