Come posso vi
convertire programmaticamente (cioè, non usare ) le nuove righe DOS / Windows in Unix?
I comandi dos2unix
e unix2dos
non sono disponibili su alcuni sistemi. Come posso emularli con comandi come sed
/ awk
/ tr
?
Come posso vi
convertire programmaticamente (cioè, non usare ) le nuove righe DOS / Windows in Unix?
I comandi dos2unix
e unix2dos
non sono disponibili su alcuni sistemi. Come posso emularli con comandi come sed
/ awk
/ tr
?
Risposte:
Puoi usare tr
per convertire da DOS in Unix; tuttavia, puoi farlo in modo sicuro solo se CR appare nel tuo file solo come primo byte di una coppia di byte CRLF. Questo di solito è il caso. Quindi utilizzare:
tr -d '\015' <DOS-file >UNIX-file
Si noti che il nome DOS-file
è diverso dal nome UNIX-file
; se provi a usare lo stesso nome due volte, finirai 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-Mper inserire control-M), allora:
sed 's/^M$//' # DOS to Unix
sed 's/$/^M/' # Unix to DOS
dove '^ M' è il carattere control-M. È inoltre possibile utilizzare il meccanismo di bash
quotazione ANSI-C 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, in parole povere), è molto più sensato installare i programmi di conversione (ad es. dos2unix
E unix2dos
, o forse dtou
e utod
) e usarli.
Se è necessario elaborare intere directory e sottodirectory, è possibile utilizzare zip
:
zip -r -ll zipfile.zip somedir/
unzip zipfile.zip
Ciò creerà un archivio zip con terminazioni di riga modificate da CRLF a CR. unzip
rimetterà quindi a posto i file convertiti (e ti chiederà file per file: puoi rispondere: Sì a tutti). Ringraziamenti a @vmsnomad per averlo segnalato.
tr -d '\015' <DOS-file >UNIX-file
where DOS-file
== UNIX-file
risulta solo un file vuoto. Il file di output deve essere un file diverso, sfortunatamente.
sed
opzione GNU -i
(per sul posto) funziona; i limiti sono file collegati e collegamenti simbolici. Il sort
comando ha 'sempre' (dal 1979, se non in precedenza) supportato l' -o
opzione che può elencare uno dei file di input. Tuttavia, ciò è in parte dovuto al fatto che sort
deve leggere tutto il suo input prima di poter scrivere qualsiasi suo output. Altri programmi supportano sporadicamente la sovrascrittura di uno dei loro file di input. È possibile trovare un programma generico (script) per evitare problemi in "L'ambiente di programmazione UNIX" di Kernighan & Pike.
sed -i $'s/\r$//' filename
- per modificare sul posto. Sto lavorando su una macchina che non ha accesso a Internet, quindi l'installazione del software è un problema.
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
Utilizzare sed -i
per la conversione sul posto, ad es sed -i 's/..../' file
.
\r
:tr "\r" "\n" < infile > outfile
-d
è descritto più frequentemente e non aiuterà nella "sola \r
" situazione.
\r
di \n
mappatura ha l'effetto di spaziare due volte i file; ogni singola riga CRLF che termina in DOS diventa \n\n
in Unix.
Farlo 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' -i inplace
opzione non è POSIX
D2U e dos2unix non sono POSIX utilità , 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 resi di trasporto:
ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx file
tr
\r
Quindi potresti anche usare printf '%s\n' '%!tr -d "\r"' x | ex file
(anche se concesso, rimosso \r
anche se non immediatamente precedente \n
). Inoltre, l' -b
opzione per ex
non è specificata da POSIX.
Puoi usare vim a livello di codice con l'opzione -c {comando}:
Dos to Unix:
vim file.txt -c "set ff=unix" -c ":wq"
Unix da dosare:
vim file.txt -c "set ff=dos" -c ":wq"
"set ff = unix / dos" significa cambiare il formato file (ff) del file nel formato di fine riga Unix / DOS
": wq" significa scrivere il file su disco ed uscire dall'editor (permettendo di usare il comando in un ciclo)
vi
saprà cosa :wq
significa. Per quelli che non significano 3 caratteri 1) apri l'area di comando vi, 2) scrivi e 3) esci.
Usando AWK puoi fare:
awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
Usando Perl puoi fare:
perl -pe 's/\r$//' < dos.txt > unix.txt
awk
.
Per convertire un file sul posto, utilizzare
dos2unix <filename>
Per generare il testo convertito in un altro file, utilizzare
dos2unix -n <input-file> <output-file>
Puoi installarlo su Ubuntu o Debian con
sudo apt install dos2unix
o su macOS usando homebrew
brew install dos2unix
Questo problema può essere risolto con strumenti standard, ma ci sono abbastanza trappole per gli inconsapevoli che ti consiglio di installare il flip
comando, che è stato scritto più di 20 anni fa da Rahul Dhesi, l'autore di zoo
. Fa un ottimo lavoro convertendo i formati di file mentre, ad esempio, evita la distruzione involontaria di file binari, il che è un po 'troppo facile se corri solo alterando ogni CRLF che vedi ...
Le soluzioni pubblicate finora affrontano solo una parte del problema, convertendo il CRLF di DOS / Windows in LF di Unix; la parte che manca è che DOS usa CRLF come separatore di linea , mentre Unix usa LF come terminatore di linea . La differenza è che un file DOS (di solito) non avrà nulla dopo l'ultima riga del file, mentre Unix lo farà. Per eseguire correttamente la conversione, è necessario aggiungere quell'LF finale (a meno che il file non abbia lunghezza zero, cioè non contenga alcuna riga). 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 'di perl:
perl -pe 'if ( s/\r\n?/\n/g ) { $f=1 }; if ( $f || ! $m ) { s/([^\n])\z/$1\n/ }; $m=1' PCfile.txt
Si noti che questo invia la versione Unixified del file a stdout. Se vuoi sostituire il file con una versione Unixified, aggiungi il -i
flag 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 <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))
Trasmissione incrociata da superutente .
dos2unix
converte tutti i file di input per impostazione predefinita. Il tuo utilizzo implica un -n
parametro. E il reale dos2unix
è un filtro che legge da stdin, scrive su stdout se i file non vengono dati.
Super duper facile con PCRE;
Come script o sostituisci $@
con i tuoi file.
#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Questo sovrascriverà i tuoi file sul posto!
Consiglio di farlo solo con un backup (controllo versione o altro)
--
. Ho scelto questa soluzione perché è facile da capire e adattarmi per me. Cordiali saluti, questo è ciò che fanno gli switch: -p
presuppone un ciclo "while input", -i
modifica il file di input sul posto, -e
esegui il seguente comando
Una soluzione awk ancora più semplice senza 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 da 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
awk -v RS='\r\n' '1' dos.txt > unix.txt
awk
o di sed
soluzione. Inoltre, è necessario utilizzare while IFS= read -r line
per preservare fedelmente le righe di input, altrimenti viene tagliato lo spazio bianco iniziale e finale (in alternativa, non utilizzare alcun nome di variabile nel read
comando e lavorare con $REPLY
).
Dovevo solo ponderare la stessa domanda (sul lato Windows, ma ugualmente applicabile a Linux). Sorprendentemente nessuno ha menzionato un modo molto automatizzato di fare la conversione CFF <-> LF per file di testo usando una buona vecchia zip -ll
opzione (Info-ZIP):
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. Poiunzip
estrarrebbe i file come compressi, cioè con i loro nomi originali (ma con terminazioni LF), spingendo così a sovrascrivere i file originali locali se presenti.
Estratto rilevante dal zip --help
:
zip --help
...
-l convert LF to CR LF (-ll CR LF to LF)
è interessante notare che nel mio git-bash su Windows sed ""
ho 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 quando legge le righe dall'input e scrive sempre le terminazioni delle linee unix sull'output.
Per Mac OSX se hai installato homebrew [ http://brew.sh/[[1]
brew install dos2unix
for csv in *.csv; do dos2unix -c mac ${csv}; done;
Assicurati di aver fatto copie dei file, poiché questo comando modificherà i file in atto. L'opzione -c mac rende lo switch compatibile con osx.
-c mac
, che è per convertire CR
solo le newline pre-OS X. Si desidera utilizzare quella modalità solo per i file da e verso Mac OS 9 o precedenti.
Puoi usare awk. Impostare il separatore record ( RS
) su una regexp che corrisponda a tutti i possibili caratteri di nuova riga o caratteri. E imposta il separatore del record di output ( ORS
) sul carattere newline in stile unix.
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
git diff
mostra ^ M, modificato in vim)
Su Linux è facile convertire ^ M (ctrl-M) in * nix newline (^ J) con sed.
Sarà qualcosa di simile sulla CLI, ci sarà effettivamente un'interruzione di riga nel testo. Tuttavia, il \ passa quel ^ J insieme a sed:
sed 's/^M/\
/g' < ffmpeg.log > new.log
Puoi ottenere ciò usando ^ V (ctrl-V), ^ M (ctrl-M) e \ (barra rovesciata) mentre digiti:
sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log
sed --expression='s/\r\n/\n/g'
Poiché la domanda menziona sed, questo è il modo più semplice per usare sed per raggiungere questo obiettivo. Quello che dice l'espressione è sostituire tutto il ritorno a capo e l'avanzamento riga con solo avanzamento riga. Questo è ciò di cui hai bisogno quando passi da Windows a Unix. Ho verificato che funziona.
Ho creato uno script basato sulla risposta accettata in modo da poterlo convertire direttamente senza bisogno di un file aggiuntivo alla fine e rimuovere e rinominare in seguito.
convert-crlf-to-lf() {
file="$1"
tr -d '\015' <"$file" >"$file"2
rm -rf "$file"
mv "$file"2 "$file"
}
assicurati solo che se hai un file come "file1.txt" che "file1.txt2" non esiste già o verrà sovrascritto, lo uso come luogo temporaneo in cui archiviare il file.
Ho provato file 's / ^ M $ //' di sed su OSX e 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 (tra Ctrl-v Invio era necessario per riprodurre ^ M). Alla fine ho usato TextWrangler. Non è strettamente riga di comando ma funziona e non si lamenta.
dos2unix
usando il gestore pacchetti, è davvero molto più semplice ed esiste sulla maggior parte delle piattaforme.