Come convertire il newline DOS / Windows (CRLF) in Unix newline (LF) in uno script Bash?

Come posso programmare a livello di codice (cioè, non usando vi ) convertire le newline DOS / Windows in Unix?

I comandi dos2unix e unix2dos non sono disponibili su alcuni sistemi. Come posso emularli con comandi come sed / awk / tr ?

Puoi usare tr per convertire da DOS a Unix; tuttavia, puoi farlo in sicurezza solo se CR appare nel tuo file solo come primo byte di una coppia di byte CRLF. Questo di solito è il caso. Quindi usi:

 tr -d '\015' UNIX-file 

Si noti che il nome DOS-file è diverso dal nome UNIX-file ; se si tenta di utilizzare lo stesso nome due volte, si finirà con nessun dato nel file.

Non puoi farlo al contrario (con lo standard ‘tr’).

Se sai come inserire il ritorno a capo in uno script ( control-V , control-M per entrare in control-M), allora:

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

dove ‘^ M’ è il carattere di controllo-M. È inoltre ansible utilizzare il meccanismo di bash ANSI-C bash per specificare il ritorno a capo:

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

Tuttavia, se devi farlo molto spesso (più di una volta, più o meno, in modo approssimativo), è molto più sensato installare i programmi di conversione (ad esempio dos2unix e unix2dos , o forse dtou e utod ) e usarli.

 tr -d "\r" < file 

dai un'occhiata qui per esempi 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 

Usa sed -i per la conversione sul posto, ad esempio il file di sed -i 's/..../' file .

Fare questo con POSIX è complicato:

  • POSIX Sed non supporta \r o \15 . Anche se così fosse, l’opzione sul posto -i non è POSIX

  • POSIX Awk supporta \r e \15 , tuttavia l’opzione -i inplace non è POSIX

  • d2u e dos2unix non sono utilità POSIX , ma ex è

  • POSIX ex non supporta \r , \15 , \n o \12

Per rimuovere i ritorni a capo:

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

Per aggiungere ritorni a capo:

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

Questo problema può essere risolto con strumenti standard, ma ci sono un numero sufficiente di trappole per gli incauti che consiglio di installare il comando flip , che è stato scritto più di 20 anni fa da Rahul Dhesi, l’autore dello zoo . Fa un ottimo lavoro nella conversione dei formati di file mentre, ad esempio, evita la distruzione involontaria dei file binari, il che è un po ‘troppo facile se si corre semplicemente a modificare ogni CRLF che si vede …

Usando AWK puoi fare:

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

Usando Perl puoi fare:

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

Le soluzioni pubblicate finora trattano solo parte del problema, convertendo il CRLF di DOS / Windows in LF di Unix; la parte che mancano è che DOS usa CRLF come separatore di riga, mentre Unix usa LF come terminatore di riga. La differenza è che un file DOS (di solito) non avrà nulla dopo l’ultima riga nel file, mentre Unix lo farà. Per eseguire correttamente la conversione, è necessario aggiungere l’ultimo LF (a meno che il file non abbia una lunghezza pari a zero, ovvero non ci siano linee in esso). Il mio incantesimo preferito per questo (con una piccola logica aggiunta per gestire i file separati da CR in stile Mac, e non i file molest che sono già in formato Unix) è un po ‘perlativo:

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

Notare che questo invia la versione Unixified del file allo stdout. Se vuoi sostituire il file con una versione Unixified, aggiungi il flag -i di perl.

Se non hai accesso a dos2unix , ma puoi leggere questa pagina, puoi copiare / incollare dos2unix.py da qui.

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

Cross-postato da superuser .

Una soluzione awk ancora più semplice con un programma:

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

Tecnicamente ‘1’ è il tuo programma, b / c awk ne richiede uno quando viene data l’opzione.

AGGIORNAMENTO : Dopo aver rivisitato questa pagina per la prima volta dopo molto tempo, mi sono reso conto che nessuno ha ancora pubblicato una soluzione interna, quindi eccone una:

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

Super duper facile con PCRE;

Come script, o sostituisci [email protected] con i tuoi file.

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

Questo sovrascriverà i tuoi file sul posto!

Consiglio di farlo solo con un backup (controllo della versione o altro)

interessante nel mio git-bash su windows sed "" ha già fatto il trucco:

 $ 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 

La mia ipotesi è che sed li ignori leggendo le righe dall’input e scriva sempre unix line endings in output.

Questo ha funzionato per me

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

Per convertire un file in atto fai

 dos2unix  

Per produrre il testo convertito in un file diverso, fare

 dos2unix -n   

È già installato su Ubuntu ed è disponibile su homebrew

 brew install dos2unix 

So che la domanda richiede esplicitamente alternative a questa utility, ma questo è il primo risultato di ricerca su google per “convertire dos in unix terminazioni di riga”.

TIMTOWTDI!

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

Basato su @GordonDavisson

Bisogna considerare la possibilità di [noeol]

Per Mac osx se hai installato homebrew [ http://brew.sh/%5D%5B1%5D

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

Assicurati di aver fatto delle copie dei file, poiché questo comando modificherà i file sul posto. L’opzione -c mac rende lo switch compatibile con osx.

Puoi usare awk. Imposta il separatore di record ( RS ) su un’espressione regolare che corrisponda a tutti i possibili caratteri o caratteri di nuova riga. E imposta il separatore dei record di uscita ( ORS ) sul carattere di nuova riga di tipo unix.

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

Come estensione della soluzione Unix a DOS di Jonathan Leffler, per convertire in sicurezza in DOS quando non si è sicuri delle terminazioni di riga del file corrente:

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

Questo controlla che la riga non finisca già in CRLF prima di convertirsi in CRLF.

Dovevo solo ponderare la stessa domanda (sul lato Windows, ma ugualmente applicabile a Linux.) Sorprendentemente nessuno ha menzionato un modo molto automatico di fare CRLF <-> Conversione LF per file di testo usando la vecchia e buona opzione zip -ll (Info- CERNIERA LAMPO):

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

NOTA: questo creerebbe un file zip preservando i nomi dei file originali ma convertendo le terminazioni di linea in LF. Quindi unzip estrarre i file come zip, cioè con i loro nomi originali (ma con terminazioni LF), chiedendo così di sovrascrivere i file originali locali, se presenti.

Estratto pertinente dallo zip --help :

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

Su Linux è facile convertire ^ M (ctrl-M) in * nix newlines (^ J) con sed.

Sarà qualcosa di simile sulla CLI, ci sarà effettivamente un’interruzione di riga nel testo. Tuttavia, il \ passa quello ^ J insieme a sed:

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

Puoi ottenere ciò usando ^ V (ctrl-V), ^ M (ctrl-M) e \ (backslash) mentre scrivi:

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

Puoi usare vim a livello di codice con l’opzione -c {comando}:

Da Dos a Unix:

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

Unix da dosare:

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

Ho provato sed ‘s / ^ M $ //’ file.txt su OSX così come molti altri metodi ( 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 ). Nessuno ha funzionato, il file è rimasto invariato (era necessario Ctrl-v Enter per riprodurre ^ M). Alla fine ho usato TextWrangler. Non è una riga di comando strettamente ma funziona e non si lamenta.

Ci sono un sacco di risposte awk / sed / etc così come un supplemento (poiché questo è uno dei risultati di ricerca principali per questo problema):

Non puoi avere dos2unix ma hai iconv ?

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

O tutti i file in una directory:

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

Questo esegue lo stesso comando, su tutti i file .sql nella cartella corrente. -o è la directory di output in modo che tu possa averlo a sostituire i file correnti, o, per ragioni di sicurezza / backup, in uscita in una directory separata.