¿Cómo convertir DOS / Windows nueva línea (CRLF) a Unix nueva línea (LF) en un script Bash?

¿Cómo puedo programáticamente (es decir, no usar vi ) convertir las líneas nuevas de DOS / Windows en Unix?

Los comandos dos2unix y unix2dos no están disponibles en ciertos sistemas. ¿Cómo puedo emular estos con comandos como sed / awk / tr ?

Puede usar tr para convertir de DOS a Unix; sin embargo, solo puede hacerlo de forma segura si CR aparece en su archivo solo como el primer byte de un par de bytes CRLF. Este suele ser el caso. Luego usas:

 tr -d '\015' UNIX-file 

Tenga en cuenta que el nombre DOS-file es diferente del nombre UNIX-file ; si intentas usar el mismo nombre dos veces, terminarás sin datos en el archivo.

No puedes hacerlo al revés (con ‘tr’ estándar).

Si sabe cómo ingresar el retorno de carro en una secuencia de comandos ( control-V , control-M para ingresar control-M), entonces:

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

donde el ‘^ M’ es el carácter de control-M. También puede usar el mecanismo bash ANSI-C Quoting para especificar el retorno de carro:

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

Sin embargo, si va a tener que hacer esto muy a menudo (más de una vez, más o menos), es mucho más sensato instalar los progtwigs de conversión (por ejemplo, dos2unix y unix2dos , o quizás dtou y utod ) y usarlos.

 tr -d "\r" < file 

echa un vistazo aquí para ejemplos usando 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 

Use sed -i para la conversión en el lugar, por ejemplo, sed -i 's/..../' file .

Hacer esto con POSIX es complicado:

  • POSIX Sed no es compatible con \r o \15 . Incluso si lo hizo, la opción in-situ no es POSIX

  • POSIX Awk admite \r y \15 ; sin embargo, la opción -i inplace no es POSIX

  • d2u y dos2unix no son utilidades POSIX , pero ex

  • POSIX ex no es compatible con \r , \15 , \n o \12

Para eliminar devoluciones de carro:

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

Para agregar retornos de carro:

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

Este problema se puede resolver con herramientas estándar, pero hay suficientes trampas para los incautos que recomiendo instalar el comando flip , que fue escrito hace más de 20 años por Rahul Dhesi, el autor del zoo . Hace un excelente trabajo al convertir formatos de archivos, mientras que, por ejemplo, evita la destrucción inadvertida de archivos binarios, lo cual es un poco fácil si solo corres para modificar cada CRLF que ves …

Usando AWK puedes hacer:

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

Usando Perl puedes hacer:

 perl -pe 's/\r$//' < dos.txt > unix.txt 

Las soluciones publicadas hasta ahora solo se ocupan de parte del problema, convirtiendo DOS / Windows ‘CRLF en LF de Unix; la parte que faltan es que DOS usa CRLF como un separador de línea, mientras que Unix usa LF como un terminador de línea. La diferencia es que un archivo DOS (por lo general) no tendrá nada después de la última línea del archivo, mientras que Unix lo hará. Para realizar la conversión correctamente, debe agregar ese LF final (a menos que el archivo sea de longitud cero, es decir, no tenga líneas en absoluto). Mi encantamiento favorito para esto (con un poco de lógica adicional para manejar archivos separados por CR de estilo Mac, y no molestar archivos que ya están en formato Unix) es un poco perl:

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

Tenga en cuenta que esto envía la versión no unificada del archivo a stdout. Si desea reemplazar el archivo con una versión no unificada, agregue el indicador -i de perl.

Si no tiene acceso a dos2unix , pero puede leer esta página, puede copiar / pegar dos2unix.py desde aquí.

 #!/usr/bin/env python """\ convert dos linefeeds (crlf) to unix (lf) usage: dos2unix.py   """ 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)) 

Publicación cruzada del superusuario .

Una solución awk aún más simple sin un progtwig:

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

Técnicamente ‘1’ es su progtwig, b / c awk requiere uno cuando se le da la opción.

ACTUALIZACIÓN : Después de volver a visitar esta página por primera vez en mucho tiempo, me di cuenta de que nadie había publicado una solución interna, así que aquí hay una:

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

Super duper fácil con PCRE;

Como script, o reemplace $@ con sus archivos.

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

¡Esto sobrescribirá tus archivos en su lugar!

Recomiendo solo hacer esto con una copia de seguridad (control de la versión o de lo contrario)

curiosamente en mi git-bash en Windows sed "" dio el truco:

 $ 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 

Mi suposición es que sed los ignora cuando lee líneas de entrada y siempre escribe terminaciones de línea Unix en la salida.

Esto funcionó para mí

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

Para convertir un archivo en su lugar, haga

 dos2unix  

Para enviar texto convertido a un archivo diferente, haga

 dos2unix -n   

Ya está instalado en Ubuntu y está disponible en homebrew

 brew install dos2unix 

Sé que la pregunta explícitamente pide alternativas a esta utilidad, pero este es el primer resultado de búsqueda de Google para “convertir dos en terminaciones de línea de Unix”.

TIMTOWTDI!

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

Basado en @GordonDavisson

Uno debe considerar la posibilidad de [noeol]

Para Mac OSX si tiene homebrew instalado [ http://brew.sh/%5D%5B1%5D

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

Asegúrese de haber hecho copias de los archivos, ya que este comando modificará los archivos en su lugar. La opción -c mac hace que el cambio sea compatible con osx.

Puedes usar awk. Establezca el separador de registros ( RS ) en una expresión regular que coincida con todos los posibles caracteres de nueva línea o caracteres. Y configure el separador de registros de salida ( ORS ) en el carácter de nueva línea al estilo de Unix.

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

Como una extensión de la solución Unix a DOS de Jonathan Leffler, para convertir de forma segura a DOS cuando no está seguro de los finales de línea actuales del archivo:

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

Esto comprueba que la línea no termina en CRLF antes de convertirse en CRLF.

Simplemente tenía que reflexionar sobre la misma pregunta (en el lado de Windows, pero igualmente aplicable a Linux.) Sorprendentemente, nadie mencionó una forma muy automatizada de hacer la conversión CRLF <-> LF para archivos de texto usando una buena opción antigua de zip -ll (Info- CREMALLERA):

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

NOTA: esto crearía un archivo zip conservando los nombres de los archivos originales pero convirtiendo los finales de línea a LF. Luego, unzip extraería los archivos como zip’ed, es decir, con sus nombres originales (pero con terminaciones LF), lo que provocaría sobrescribir los archivos originales locales, si los hubiera.

Extracto relevante del zip --help :

 zip --help ... -l convert LF to CR LF (-ll CR LF to LF) 

En Linux es fácil convertir ^ M (ctrl-M) a * nix nuevas líneas (^ J) con sed.

Será algo así en la CLI, en realidad habrá un salto de línea en el texto. Sin embargo, el \ pasa ese ^ J junto a sed:

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

Obtienes esto usando ^ V (ctrl-V), ^ M (ctrl-M) y \ (barra invertida) mientras escribes:

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

Puede usar vim programáticamente con la opción -c {comando}:

Dos a Unix:

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

Unix a dos:

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

Probé sed / ^ M $ // ‘file.txt en OSX así como varios otros métodos ( http://www.thingy-ma-jig.co.uk/blog/25-11-2010/fixing- dos-line-endings o http://hintsforums.macworld.com/archive/index.php/t-125.html ). Ninguno funcionó, el archivo se mantuvo sin cambios (por cierto, Ctrl-v Enter fue necesario para reproducir ^ M). Al final usé TextWrangler. No es estrictamente una línea de comandos, pero funciona y no se queja.

Hay muchas respuestas awk / sed / etc, así como un suplemento (ya que este es uno de los principales resultados de búsqueda para este problema):

Puede que no tenga dos2unix, pero ¿tiene iconv ?

 iconv -f UTF-16LE -t UTF-8 [filename.txt] -f from format type -t to format type 

O todos los archivos en un directorio:

 find . -name "*.sql" -exec iconv -f UTF-16LE -t UTF-8 {} -o ./{} \; 

Esto ejecuta el mismo comando, en todos los archivos .sql en la carpeta actual. -o es el directorio de salida, por lo que puede hacer que reemplace los archivos actuales o, por razones de seguridad / respaldo, enviar a un directorio diferente.