web-dev-qa-db-fra.com

Comment convertir une nouvelle ligne DOS/Windows (CRLF) en nouvelle ligne Unix (LF) dans un script Bash?

Comment puis-je convertir par programmation (c'est-à-dire sans utiliser vi) les nouvelles lignes DOS/Windows en Unix?

Les commandes dos2unix et unix2dos ne sont pas disponibles sur certains systèmes. Comment puis-je les émuler avec des commandes telles que sed/awk/tr?

276
Koran Molovik

Vous pouvez utiliser tr pour convertir de DOS en Unix; Toutefois, vous ne pouvez le faire en toute sécurité que si CR apparaît dans votre fichier uniquement en tant que premier octet d'une paire d'octets CRLF. C'est généralement le cas. Vous utilisez alors:

tr -d '\015' <DOS-file >UNIX-file

Notez que le nom DOS-file est différent du nom UNIX-file; si vous essayez d'utiliser le même nom deux fois, vous vous retrouverez sans données dans le fichier.

Vous ne pouvez pas le faire dans l’inverse (avec le "tr" standard).

Si vous savez entrer un retour chariot dans un script (control-Vcontrol-M entrer dans control-M), puis:

sed 's/^M$//'     # DOS to Unix
sed 's/$/^M/'     # Unix to DOS

où "^ M" est le caractère de contrôle-M. Vous pouvez également utiliser le mécanisme bashcitation ANSI-C pour spécifier le retour à la ligne:

sed $'s/\r$//'     # DOS to Unix
sed $'s/$/\r/'     # Unix to DOS

Cependant, si vous devez le faire très souvent (plus d'une fois, en gros), il est beaucoup plus judicieux d'installer les programmes de conversion (par exemple, dos2unix et unix2dos , ou peut-être dtou et utod ) et les utiliser.

299
Jonathan Leffler
tr -d "\r" < file

jetez un coup d'oeil ici pour des exemples utilisant sed:

# IN UNIX ENVIRONMENT: convert DOS newlines (CR/LF) to Unix format.
sed 's/.$//'               # assumes that all lines end with CR/LF
sed 's/^M$//'              # in bash/tcsh, press Ctrl-V then Ctrl-M
sed 's/\x0D$//'            # works on ssed, gsed 3.02.80 or higher

# IN UNIX ENVIRONMENT: convert Unix newlines (LF) to DOS format.
sed "s/$/`echo -e \\\r`/"            # command line under ksh
sed 's/$'"/`echo \\\r`/"             # command line under bash
sed "s/$/`echo \\\r`/"               # command line under zsh
sed 's/$/\r/'                        # gsed 3.02.80 or higher

Utilisez sed -i pour la conversion sur place, par exemple. sed -i 's/..../' file.

53
ghostdog74

Faire cela avec POSIX est délicat:

  • POSIX Sed ne prend pas en charge \r ni \15. Même si c'était le cas, l'option en place -i n'est pas POSIX.

  • POSIX Awk prend en charge \r et \15, mais l'option -i inplaceis n'est pas POSIX

  • d2u et dos2unix ne sont pas utilitaires POSIX , mais ex est

  • POSIX ex ne prend pas en charge \r, \15, \n ou \12

Pour supprimer les retours chariot:

ex -bsc '%!awk "{sub(/\r/,\"\")}1"' -cx file

Pour ajouter des retours chariot:

ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx file
36
Steven Penny

En utilisant AWK, vous pouvez faire:

awk '{ sub("\r$", ""); print }' dos.txt > unix.txt

En utilisant Perl, vous pouvez faire:

Perl -pe 's/\r$//' < dos.txt > unix.txt
20
codaddict

Ce problème peut être résolu avec des outils standard, mais il y a suffisamment de pièges pour les imprudents que je vous recommande d'installer la commande flip , écrite il y a plus de 20 ans par Rahul Dhesi, l'auteur de Zoo. Il fait un excellent travail de conversion des formats de fichiers tout en évitant, par exemple, la destruction par inadvertance de fichiers binaires, ce qui est un peu trop facile si vous vous contentez de modifier tous les CRLF que vous voyez ...

19
Norman Ramsey

Les solutions publiées jusqu’à présent ne traitent qu’une partie du problème, à savoir la conversion du CRLF de DOS/Windows en LF d’Unix; la partie qui leur manque est que DOS utilise CRLF en tant que ligne séparateur , tandis qu'Unix utilise LF en tant que ligne terminateur . La différence est qu'un fichier DOS (généralement) n'aura rien après la dernière ligne du fichier, contrairement à Unix. Pour effectuer la conversion correctement, vous devez ajouter le LF final (sauf si le fichier a une longueur égale à zéro, c’est-à-dire qu’il ne contient aucune ligne du tout). Mon incantation préférée pour cela (avec un peu de logique supplémentaire pour manipuler des fichiers séparés par un CR de style Mac, et non pour molester des fichiers qui sont déjà au format unix) est un peu Perl:

Perl -pe 'if ( s/\r\n?/\n/g ) { $f=1 }; if ( $f || ! $m ) { s/([^\n])\z/$1\n/ }; $m=1' PCfile.txt

Notez que cela envoie la version Unixified du fichier à stdout. Si vous souhaitez remplacer le fichier par une version Unixified, ajoutez l'indicateur -i de Perl.

14
Gordon Davisson

Si vous n'avez pas accès à dos2unix, mais pouvez lire cette page, vous pouvez copier/coller dos2unix.py à partir d'ici.

#!/usr/bin/env python
"""\
convert dos linefeeds (crlf) to unix (lf)
usage: dos2unix.py <input> <output>
"""
import sys

if len(sys.argv[1:]) != 2:
  sys.exit(__doc__)

content = ''
outsize = 0
with open(sys.argv[1], 'rb') as infile:
  content = infile.read()
with open(sys.argv[2], 'wb') as output:
  for line in content.splitlines():
    outsize += len(line) + 1
    output.write(line + '\n')

print("Done. Saved %s bytes." % (len(content)-outsize))

Cross-posted from superuser .

12
anatoly techtonik

Super duper facile avec PCRE;

En tant que script, ou remplacez $@ par vos fichiers.

#!/usr/bin/env bash
Perl -pi -e 's/\r\n/\n/g' -- $@

Cela écrasera vos fichiers en place!

Je recommande de ne faire cela qu'avec une sauvegarde (contrôle de version ou autre)

8
ThorSummoner

Une solution awk encore plus simple sans programme:

awk -v ORS='\r\n' '1' unix.txt > dos.txt

Techniquement '1' est votre programme, b/c awk en nécessite un lorsque l'option vous est donnée. 

UPDATE: Après avoir consulté cette page pour la première fois depuis longtemps, je me suis rendu compte que personne n’avait encore posté de solution interne, en voici une:

while IFS= read -r line;
do printf '%s\n' "${line%$'\r'}";
done < dos.txt > unix.txt
6
nawK

Vous pouvez utiliser vim par programme avec l'option -c {commande}:

Dos à Unix:

vim file.txt -c "set ff=unix" -c ":wq"

Unix à dos:

vim file.txt -c "set ff=dos" -c ":wq"

"set ff = unix/dos" signifie changer le format de fichier (ff) du fichier au format de fin de ligne Unix/DOS

": wq" signifie écrire un fichier sur le disque et quitter l'éditeur (permettant d'utiliser la commande dans une boucle)

5
Johan Zicola

Pour convertir un fichier en place, faites

dos2unix <filename>

Pour convertir le texte converti dans un autre fichier, faites

dos2unix -n <input-file> <output-file>

Il est déjà installé sur Ubuntu et est disponible sur homebrew avec brew install dos2unix


Je sais que la question demande explicitement d’autres solutions que cet utilitaire, mais c’est le premier résultat de recherche de Google pour "convertir les fins de ligne Unix".

4
Boris

fait intéressant dans mon git-bash sur Windows sed "" a déjà fait le tour:

$ echo -e "abc\r" >tst.txt
$ file tst.txt
tst.txt: ASCII text, with CRLF line terminators
$ sed -i "" tst.txt
$ file tst.txt
tst.txt: ASCII text

Je suppose que sed les ignore lors de la lecture des lignes depuis l'entrée et écrit toujours les fins de ligne Unix en sortie.

4
user829755

Cela a fonctionné pour moi 

tr "\r" "\n" < sampledata.csv > sampledata2.csv 
3
Santosh

TIMTOWTDI!

Perl -pe 's/\r\n/\n/; s/([^\n])\z/$1\n/ if eof' PCfile.txt

Basé sur @GordonDavisson

Il faut envisager la possibilité de [noeol] ...

2
lzc

Il fallait juste réfléchir à la même question (côté Windows, mais également applicable à Linux.) Étonnamment, personne n’a mentionné une méthode très automatisée de conversion CRLF <-> LF pour les fichiers texte utilisant la bonne vieille option Zip -ll (Info -Zip *: français):

Zip -ll textfiles-lf.Zip files-with-crlf-eol.*
unzip textfiles-lf.Zip 

REMARQUE: cela créerait un fichier Zip en conservant les noms de fichier d'origine, mais en convertissant les fins de ligne en LF. Ensuite, unzip extrairait les fichiers selon le format compressé, c'est-à-dire avec leurs noms d'origine (mais avec des fins LF), invitant ainsi à remplacer les fichiers d'origine locaux, le cas échéant.

Extrait pertinent du Zip --help:

Zip --help
...
-l   convert LF to CR LF (-ll CR LF to LF)
2
vmsnomad

Vous pouvez utiliser awk. Définissez le séparateur d'enregistrement (RS) sur une expression rationnelle qui correspond à tous les caractères de nouvelle ligne possibles. Et définissez le séparateur d'enregistrement de sortie (ORS) sur le caractère de nouvelle ligne de style unix.

awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
1
kazmer

Pour Mac OSX si vous avez installé homebrew [ http://brew.sh/][1]

brew install dos2unix

for csv in *.csv; do dos2unix -c mac ${csv}; done;

Vérifiez que vous avez bien copié les fichiers, car cette commande modifiera les fichiers en place . L'option -c mac rend le commutateur compatible avec osx.

1
Ashley Raiteri

Sous Linux, il est facile de convertir ^ M (ctrl-M) en * nix newlines (^ J) avec sed.

Ce sera quelque chose comme ceci sur la CLI, il y aura en fait un saut de ligne dans le texte. Cependant, le\passe que ^ J le long de sed:

sed 's/^M/\
/g' < ffmpeg.log > new.log

Vous obtenez cela en utilisant ^ V (ctrl-V), ^ M (ctrl-M) et\(barre oblique inverse) lorsque vous tapez:

sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log
1
jet

En tant qu'extension de la solution Unix vers DOS de Jonathan Leffler, pour convertir en toute sécurité en DOS lorsque vous n'êtes pas sûr des fins de ligne du fichier

sed '/^M$/! s/$/^M/'

Ceci vérifie que la ligne ne se termine pas déjà par CRLF avant d'être convertie en CRLF.

0
Gannet

J'ai créé un script en fonction de la réponse acceptée afin que vous puissiez le convertir directement sans avoir besoin d'un fichier supplémentaire, puis supprimer et renommer.

convert-crlf-to-lf() {
    file="$1"
    tr -d '\015' <"$file" >"$file"2
    rm -rf "$file"
    mv "$file"2 "$file"
}

assurez-vous simplement que si vous avez un fichier comme "fichier1.txt" que "fichier1.txt2" n'existe pas déjà ou qu'il sera écrasé, je l'utilise comme emplacement temporaire pour stocker le fichier.

0
OZZIE
sed --expression='s/\r\n/\n/g'

Étant donné que la question mentionne sed, il s'agit du moyen le plus simple d'utiliser sed pour atteindre cet objectif. Ce que l'expression dit, c'est remplacer tout retour chariot et saut de ligne par un saut de ligne uniquement. C'est ce dont vous avez besoin lorsque vous passez de Windows à Unix. J'ai vérifié que ça marche.

0
John Paul