2010-04-10 27 views
226

¿Cómo puedo programáticamente (es decir, no usar vi) convertir 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?Cómo convertir DOS/Windows nueva línea (CRLF) a Unix nueva línea ( n) en un script Bash?

+0

Si puede compilar en el sistema de destino, puede intentar https://github.com/mdolidon/endlines; está hecho para ser bastante portátil. –

+5

En general, simplemente instale 'dos2unix' usando su administrador de paquetes, realmente es mucho más simple y existe en la mayoría de las plataformas. –

Respuesta

15

Utilizando AWK que puede hacer:

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

Utilizando Perl que puede hacer:

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

Una solución agradable, _portable_ 'awk'. – mklement0

243

Se puede utilizar para convertir tr 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. A continuación se usa:

tr -d '\015' <DOS-file >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 puede hacerlo al revés (con 'tr' estándar).

Si sabe cómo introducir retorno de carro en un guión (de control-V, Control-M para entrar en Control-M), entonces:

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

donde el '^ M' es el caracter de control-M También puede utilizar el mecanismo bashANSI-C Quoting para especificar el retorno de carro:

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

Sin embargo, si usted va a tener que hacer esto muy a menudo (más de una vez, en términos generales), es mucho más sensato instale los programas de conversión (por ejemplo, dos2unix y unix2dos, o quizás dtou y utod) y úselos.

+3

usando 'tr -d '\ 015' UNIX-file' donde' DOS-file' == 'UNIX-file' solo da como resultado un archivo vacío. El archivo de salida tiene que ser un archivo diferente, desafortunadamente. –

+2

@ButtleButkus: Bueno, sí; es por eso que utilicé dos nombres diferentes. Si borra el archivo de entrada antes de que el programa lo lea todo, como hace cuando usa el mismo nombre dos veces, termina con un archivo vacío. Ese es un comportamiento uniforme en sistemas tipo Unix. Requiere un código especial para manejar la sobrescritura de un archivo de entrada de forma segura. Sigue las instrucciones y estarás bien. –

+0

Me parece recordar alguna función de búsqueda-reemplazo dentro del archivo. –

46
tr -d "\r" < file 

echar un vistazo 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 

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

+9

Utilicé una variante ya que mi archivo solo tenía '\ r':' tr "\ r" "\ n" < infile > archivo de salida' –

+0

@MattTodd ¿podría publicar esto como respuesta? el '-d' aparece con más frecuencia y no ayudará en la situación" only '\ r'". – n611x007

+2

Tenga en cuenta que la asignación propuesta '\ r' a' \ n' tiene el efecto de doble espaciado de los archivos; cada línea CRLF que termina en DOS se convierte en '\ n \ n' en Unix. –

14

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 una línea separador, mientras que Unix usa LF como una línea terminador. 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 favorito para este encantamiento (con un poco de lógica adicional para gestionar archivos CR-separado de estilo Mac, y no molestar a los archivos ya that're en formato UNIX) es un poco de 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 Unixified del archivo a stdout. Si desea reemplazar el archivo con una versión no unificada, agregue el indicador -i de perl.

+0

RIP mi archivo de datos. se equivocó en algún lugar xD –

+0

@LudovicZenohateLagouardette ¿Se trataba de un archivo de texto sin formato (es decir, csv o texto con tabulación), o alguna otra cosa? Si estaba en algún formato ish de base de datos, manipularlo como si fuera texto es muy probable que dañe su estructura interna. –

+0

Un csv de texto sin formato, pero creo que el descubrimiento fue extraño. Creo que fue un desastre debido a eso. Sin embargo, no te preocupes. Siempre estoy recopilando copias de seguridad y este ni siquiera era el conjunto de datos real, solo un archivo de 1 gb. Lo real es 26 gb. –

18

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 de zoo. Se hace un trabajo excelente conversión de formatos de archivo, mientras que, por ejemplo, evitar la destrucción inadvertida de archivos binarios, que es un poco demasiado fácil si sólo Carrera alrededor de la alteración de cada CRLF ves ...

+0

¿Alguna manera de hacer esto de forma continua, sin modificar el archivo original? – augurar

+0

@augurar puede consultar "paquetes similares" https://packages.debian.org/wheezy/flip – n611x007

9

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

#!/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)) 

Publicación cruzada desde superuser.

+0

El uso es engañoso. El verdadero 'dos2unix' convierte * todos * los archivos de entrada por defecto. Su uso implica el parámetro '-n'. Y el 'dos2unix' real es un filtro que lee de stdin, escribe en stdout si no se proporcionan los archivos. – jfs

+1

@ J.F.Sebastian que 'dos2unix' herramientas es real? ¿Está en el estándar POSIX? –

+0

¿Qué 'dos2unix' quieres decir? Quise decir: 'sudo apt-get install dos2unix' – jfs

34

Hacer esto con POSIX es complicado:

  • POSIX Sed no admite \r o \15. Incluso si lo hiciera, la opción en su lugar -i no es POSIX

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

  • d2u y dos2unix no son POSIX utilities, pero ex es

  • POSIX ex no soporta \r, \15, \n o \12

Para quitar los retornos de carro:

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

Para añadir retornos de carro:

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

Parece que [POSIX 'tr' admite' \ r'.] (Http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html#tag_20_132_13) Así que también puede usar 'printf '% s \ n ''%! tr -d "\ r" 'x | ex file' (aunque se concede, esto elimina '\ r' incluso si no está inmediatamente antes de' \ n'). Además, la opción '-b' a' ex' no está especificada por POSIX. – Wildcard

0

Para Mac OS X si ha instalado homebrew [http://brew.sh/][1]

brew install dos2unix 

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

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

+0

'dos2unix' resultó ser bastante útil. – HelloGoodbye

+0

Esta respuesta realmente no es la pregunta del cartel original. – hlin117

+1

Los usuarios de OS X no deben usar '-c mac', que es para convertir líneas nuevas' 'solo'' de OS-X. Desea utilizar ese modo solo para archivos hacia y desde Mac OS 9 o anteriores. – askewchan

6

Una solución awk aún más simple w/o un programa:

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

Técnicamente '1' es su programa, b/c awk requiere que uno cuando se les da la opción.

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

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

Eso es útil, pero solo para ser claro: esto traduce Unix -> Windows/DOS, que es la dirección opuesta a lo que solicitó el OP. – mklement0

+5

Fue hecho a propósito, dejado como ejercicio para el autor. _eyerolls_ 'awk -v RS = '\ r \ n' '1' dos.txt> unix.txt' – nawK

+0

Estupendo (y felicitaciones para la finura pedagógica). – mklement0

3

Esto funcionó para mí

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

Esto convertirá cada _single_ DOS-newline en _two_ UNIX-newlines. – Melebius

5

Super duper easy with PCRE;

Como un script, o reemplace [email protected] con sus archivos.

#!/usr/bin/env bash 
perl -pi -e 's/\r\n/\n/g' -- [email protected] 

Esto sobrescribirá sus archivos en su lugar!

solo recomiendo hacer esto con una copia de seguridad (control de versiones o de otra manera)

+0

¡Gracias! Esto funciona, aunque estoy escribiendo el nombre de archivo y no '--'. Elegí esta solución porque es fácil de entender y adaptar para mí. FYI, esto es lo que hacen los conmutadores: '-p' suponen un bucle" while input ",' -i' edit archivo de entrada en su lugar, '-e' ejecutan el siguiente comando – Rolf

+0

Estrictamente hablando, PCRE es una reimplementación de Perl motor regex, no el motor regex de Perl. Ambos tienen esta capacidad, aunque también hay diferencias, a pesar de la implicación en el nombre. – tripleee

1

TIMTOWTDI!

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

Basado en @GordonDavisson

se debe considerar la posibilidad de [noeol] ...

1

Puede usar awk. Establezca el separador de registros (RS) en una expresión regular que coincida con todos los posibles caracteres o caracteres de nueva línea. Y configure el separador de registro 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 
+0

Eso es lo que funcionó para mí (MacOS, 'git diff' muestra^M, editado en vim) – Dorian

0

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

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

Esto comprueba que la línea no hace ya terminar en CRLF antes de convertir a CRLF.

0

acababa de ponderar la misma pregunta Sorprendentemente nadie mencionó una manera mucho automatizado de hacer CRLF < (en Windows a lado, pero igualmente aplicable a Linux.) -> conversión de LF para archivos de texto usando buena opción edad zip -ll (Info-ZIP):

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

NOTA: esto crearía un archivo zip preservar los nombres de los archivos originales, pero la conversión de 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 de la zip --help:

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

interesante en mi git-bash en ventanas sed "" hizo el truco ya:

$ 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 conjetura es que el SED los ignora al leer las líneas de entrada y siempre escribe finales de línea Unix en la salida.

-3

Hay un montón de awk/sed/etc respuestas de manera que un suplemento (ya que este es uno de los mejores resultados de búsqueda para este tema):

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 va en el mismo comando, en todos los archivos .sql de 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.

+1

Esto intenta lograr la conversión de codificación de UTF-16LE a UTF-8, pero no toca las terminaciones de línea.No tiene nada que ver con la pregunta que se hace. – Palec

+0

Mi mal. Voy a verificar esto, pero, acabo de utilizar ESE DÍA para solucionar mi problema de grep no se ejecuta en mis archivos porque tenían formato de Windows. –

+1

También es un problema común, pero no el problema que el OP está preguntando (y bastante menos común que el problema CRLF). – tripleee