Bir Bash betiğinde DOS / Windows satırsonu (CRLF) Unix satırsonu (LF) dönüştürmek nasıl?


336

viDOS / Windows satırlarını programlı olarak Unix'e nasıl dönüştürebilirim (örneğin, kullanmıyorum )?

dos2unixVe unix2doskomutlar belirli sistemlerde kullanılamaz. Bunları sed/ awk/ gibi komutlarla nasıl taklit edebilirim tr?


9
Genel olarak, dos2unixpaket yöneticinizi kullanarak yükleyin , gerçekten çok daha basittir ve çoğu platformda mevcuttur.
Brad Koch

1
Kabul! @BradKoch Mac OSX'te 'demlemek kurulum dos2unix' olarak basit
SmileIT

Yanıtlar:


323

trDOS'tan Unix'e dönüştürmek için kullanabilirsiniz ; ancak, bunu CR dosyanızda yalnızca bir CRLF bayt çiftinin ilk baytı olarak görünüyorsa yapabilirsiniz. Bu genellikle böyledir. Daha sonra şunları kullanırsınız:

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

Adın DOS-fileaddan farklı olduğunu unutmayın UNIX-file; aynı adı iki kez kullanmaya çalışırsanız, dosyada veri olmaz.

Bunu başka türlü yapamazsınız (standart 'tr' ile).

Bir komut dosyasına satır başı nasıl girileceğini biliyorsanız ( control-V,control-M control-M girmek için), o zaman:

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

burada '^ M' kontrol-M karakteridir. bash ANSI-C Alıntılama mekanizmasını, satır başını belirtmek için de kullanabilirsiniz :

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

Bununla birlikte, bunu çok sık yapmak zorunda kalacaksanız (bir kereden fazla, kabaca konuşursak), dönüşüm programlarını yüklemek çok daha mantıklıdır (ör. dos2unixVe unix2dos, veya belki dtouveutod ) ve kullanmak .

Tüm dizinleri ve alt dizinleri işlemeniz gerekiyorsa, şunları kullanabilirsiniz zip:

zip -r -ll zipfile.zip somedir/
unzip zipfile.zip

Bu satır sonları CRLF'den CR'ye değiştirilmiş bir zip arşivi oluşturur. unzipdaha sonra dönüştürülen dosyaları tekrar yerine koyacaktır (ve dosyaya göre dosya soracaksınız - yanıtlayabilirsiniz: Herkese evet). Bunu işaret ettiği için @vmsnomad'a verilen krediler.


9
tr -d '\015' <DOS-file >UNIX-filewhere DOS-file== kullanmak UNIX-fileyalnızca boş bir dosya ile sonuçlanır. Çıktı dosyası maalesef farklı bir dosya olmalıdır.
Buttle Butkus

3
@ButtleButkus: Evet, evet; bu yüzden iki farklı isim kullandım. Aynı dosyayı iki kez kullandığınızda yaptığınız gibi, programın tümünü okumadan önce girdi dosyasını zap yaparsanız, boş bir dosya elde edersiniz. Bu, Unix benzeri sistemlerde tek biçimli davranıştır. Giriş dosyasının üzerine yazma işlemlerini güvenli bir şekilde yapmak için özel bir kod gerektirir. Talimatları izleyin ve iyi olacaksınız.
Jonathan Leffler

Somehwere dosya içi arama değiştirme işlevselliğini hatırlıyorum.
Buttle Butkus

4
Yerler var; onları nerede bulacağınızı bilmelisiniz. Sınırlar içinde, GNU sedseçeneği -i(yerinde) çalışır; limitler bağlantılı dosyalar ve sembolik linklerdir. sortKomut 'daima' vardır (1979 yılından bu yana, erken değil ise) desteklenen -ogirdi dosyalardan birini listeleyebilirsiniz seçeneği. Ancak bu kısmen sort, çıktılarından herhangi birini yazmadan önce tüm girdilerini okumalıdır. Diğer programlar ara sıra girdi dosyalarından birinin üzerine yazmayı destekler. Kernighan & Pike'ın 'UNIX Programlama Ortamı' bölümünde problemlerden kaçınmak için genel amaçlı bir program (script) bulabilirsiniz .
Jonathan Leffler

3
Üçüncü seçenek benim için çalıştı, teşekkürler. sed -i $'s/\r$//' filenameYerinde düzenlemek için -i seçeneğini kullandım: -. İnternet erişimi olmayan bir makine üzerinde çalışıyorum, bu yüzden yazılım kurulumu bir sorun.
Warren Dew

64
tr -d "\r" < file

bir göz atın burada kullanarak örnekler için 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

sed -iYerinde dönüşüm için kullanın örn sed -i 's/..../' file.


10
Dosyamın sahip olduğu için bir varyant kullandım \r:tr "\r" "\n" < infile > outfile
Matt Todd

1
@MattTodd bunu bir cevap olarak gönderebilir misiniz? -ddaha sık özellikli ve "sadece yardımcı olmayacaktır \r" durum.
n611x007

5
Önerdiği Not \riçin \nharitalama çift aralık dosyaların etkisi vardır; DOS ile biten her bir CRLF satırı \n\nUnix'te olur .
Jonathan Leffler

Bunu tekrar tekrar yapabilir miyim?
Aaron Franke

36

POSIX ile bunu yapmak zor:

Satır başlarını kaldırmak için:

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

Satır başı eklemek için:

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

2
POSIX trdesteklerine\r benziyor . Böylece kullanabilirsiniz printf '%s\n' '%!tr -d "\r"' x | ex file(kabul edilmiş olsa da, \rhemen öncesinde olmasa bile kaldırıldı \n). Ayrıca, POSIX tarafından -bseçeneği exbelirtilmedi.
Joker

1
POSIX'te bunu yapmak kolaydır. CR değişmezini komut dosyasına yazarak yerleştirin (control-M).
Joshua

28

Vim'yi -c {command} seçeneğiyle programlı olarak kullanabilirsiniz:

Dos Unix için:

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

Unix to dos:

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

"set ff = unix / dos", dosyanın dosya biçimini (ff) Unix / DOS satır sonu biçimine değiştir anlamına gelir

": wq", diske dosya yazmak ve düzenleyiciden çıkmak (komutu bir döngüde kullanmaya izin vermek) anlamına gelir


3
Bu en zarif çözüm gibi görünüyordu ama wq'un ne anlama geldiğine dair açıklama eksikliği talihsiz.
Jorrick Sleijster

5
Kullanan herkes vine :wqanlama geldiğini bilir . 3 karakteri olmayanlar için 1) açık vi komut alanı, 2) yazma ve 3) çıkış.
David Newcomb


": wq" yerine ": x" kullanabilirsiniz
JosephConrad

25

AWK kullanarak şunları yapabilirsiniz:

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

Perl kullanarak şunları yapabilirsiniz:

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

2
Güzel, taşınabilir bir awk çözüm.
mklement0

24

Bir dosyayı yerinde dönüştürmek için

dos2unix <filename>

Dönüştürülen metni farklı bir dosyaya çıkarmak için

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

Ubuntu veya Debian'a şu şekilde yükleyebilirsiniz:

sudo apt install dos2unix

veya homebrew kullanarak macOS'ta

brew install dos2unix

1
Sorunun dos2unix'e alternatifler istediğini biliyorum ama ilk google sonucu.
Boris

18

Bu sorun standart araçlarla çözülebilir, ancak flip20 yıl önce yazarı Rahul Dhesi tarafından yazılan komutu yüklemenizi tavsiye ettiğim için yeterince fazla tuzak var zoo. Örneğin, ikili dosyaların yanlışlıkla tahrip edilmesinden kaçınırken, dosya formatlarını dönüştüren mükemmel bir iş çıkarır;


Orijinal dosyayı değiştirmeden bunu akış şeklinde yapmanın herhangi bir yolu var mı?
augurar

@augurar "benzer paketler" paketlerini
n611x007

İşletim sistemimin yarısını yanlış bir bayrakla texxto çalıştırarak tecrübe ettim. Özellikle tüm klasörlerde yapmak istiyorsanız dikkatli olun.
A_P

14

Şimdiye kadar yayınlanan çözümler, sorunun sadece bir kısmı ile ilgileniyor ve DOS / Windows CRLF'yi Unix'in LF'sine dönüştürüyor; eksik oldukları kısım DOS'un satır ayırıcısı olarak CRLF kullanması , Unix ise bir satır sonlandırıcısı olarak LF kullanmasıdır . Fark, bir DOS dosyasının (genellikle) dosyadaki son satırdan sonra hiçbir şeye sahip olmaması, Unix'in ise olmasıdır. Dönüştürmeyi düzgün bir şekilde yapmak için, son LF'yi eklemeniz gerekir (dosya sıfır uzunlukta değilse, yani içinde hiç satır yoksa). Bunun için en sevdiğim büyüm (Mac stili CR ile ayrılmış dosyaları işlemek için biraz eklenmiş mantıkla ve zaten unix biçiminde olan taciz dosyalarını değil) biraz perl:

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

Bunun, dosyanın Unixified sürümünü stdout'a gönderdiğini unutmayın. Dosyayı Unixified sürümüyle değiştirmek istiyorsanız perl'in -ibayrağını ekleyin .


@LudovicZenohateLagouardette Düz bir metin dosyası mı (örn. Csv veya sekmeyle indirilmiş metin) veya başka bir şey mi? Bazı veritabanı-ish biçimindeyse, sanki metinmiş gibi işlemesi iç yapısını bozma olasılığı çok yüksektir.
Gordon Davisson

Düz bir metin csv, ama sanırım çevresi garipti. Bence bu yüzden berbat oldu. Ancak endişelenme. Her zaman yedekleri topluyorum, bu gerçek veri seti bile değildi, sadece 1GB. Gerçek 26gb.
Ludovic Zenohate Lagouardette

14

Dos2unix'e erişiminiz yoksa ancak bu sayfayı okuyabiliyorsanız, dos2unix.py'yi buradan kopyalayabilir / yapıştırabilirsiniz .

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

Süper kullanıcıdan çapraz gönderi .


1
Kullanımı yanıltıcıdır. Real dos2unix, varsayılan olarak tüm girdi dosyalarını dönüştürür . Kullanımınız -nparametre anlamına gelir . Ve gerçek dos2unixstdin'den okunan, dosyalar verilmezse stdout'a yazan bir filtredir.
jfs

8

PCRE ile süper duper kolay;

Komut dosyası olarak veya $@dosyalarınızla değiştirin .

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

Bu, dosyalarınızın üzerine yazacaktır!

Bunu yalnızca bir yedeklemeyle (sürüm kontrolü veya başka bir şekilde) yapmanızı öneririm


Teşekkür ederim! Ben dosya adını yazıyorum ve hayır rağmen bu çalışır --. Bu çözümü seçtim, çünkü benim için anlaşılması ve uyarlanması kolay. FYI, anahtarların yaptığı şey budur: -p"while input" döngüsünü varsayalım, -igirdi dosyasını yerinde düzenleyin, -eaşağıdaki komutu yürütün
Rolf

Açıkçası PCRE, Perl'in normal ifade motorunun değil, Perl normal ifade motorunun yeniden uygulanmasıdır. Her ikisi de bu yeteneğe sahiptir, ancak isimdeki imaya rağmen farklılıklar da vardır.
üçlü

6

Programsız daha basit bir awk çözümü:

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

Teknik olarak '1' sizin programınızdır, b / c awk seçeneği verildiğinde bir tane gerektirir.

GÜNCELLEME : Bu sayfayı uzun süre ilk kez tekrar ziyaret ettikten sonra, henüz hiç kimsenin dahili bir çözüm yayınlamadığını fark ettim, işte burada:

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

Bu kullanışlı, ancak sadece açık olmak gerekirse: bu , OP'nin istediği yönün tersi olan Unix -> Windows / DOS'u çevirir .
mklement0

5
Amaç için yapıldı, yazar için bir egzersiz olarak bırakıldı. eyerolls awk -v RS='\r\n' '1' dos.txt > unix.txt
nawK

Büyük (ve pedagojik incelik için size kudos).
mklement0

1
msgstr "b / c awk seçenek verildiğinde bir tane gerektirir." - awk seçenekleri belirtilmiş olsun olmasın her zaman bir program gerektirir.
mklement0

1
Saf bash çözeltisi ilginçtir, ancak eşdeğer awkveya sedçözeltiden çok daha yavaştır . Ayrıca, while IFS= read -r linegiriş satırlarını sadakatle korumak için kullanmalısınız , aksi takdirde öndeki ve sondaki boşluk kesilir (alternatif olarak readkomutta değişken adı kullanmayın ve onunla çalışın $REPLY).
mklement0

5

Sadece aynı soruyu düşünmek zorunda kaldım (Windows tarafında, ancak linux için eşit derecede uygulanabilir.) Şaşırtıcı kimse, eski eski zip -llseçeneği (Info-ZIP) kullanarak metin dosyaları için CRLF <-> LF dönüşümü yapmanın çok otomatik bir yolundan bahsetmedi :

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

NOT: Bu, orijinal dosya adlarını koruyan ancak satır sonlarını LF'ye dönüştüren bir zip dosyası oluşturur. Sonraunzip dosyaları zip'ed olarak, yani orijinal isimleriyle (ancak LF uçlarıyla) ayıklayın, böylece varsa yerel orijinal dosyaların üzerine yazılmasını isteyin.

İlgili alıntı zip --help:

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

Bana göre en iyi cevap, tüm dizinleri ve alt dizinleri işleyebileceğinden. Bunu çok kazdýđým için memnunum.
caram

5

ilginç Windows benim git-bash sed ""hile zaten yaptı:

$ 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

Benim tahminim sed giriş satırları okurken onları görmezden gelir ve her zaman çıkış üzerine unix satır sonları yazar.


4

Bu benim için çalıştı

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

9
Bu, her dönüştürür tek içine DOS yeni satır iki UNIX satırbaşıyla.
Melebius

2

Mac osx için homebrew yüklüyse [ http://brew.sh/ürlü[1]

brew install dos2unix

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

Bu komut, dosyaları yerinde değiştireceğinden dosyaların kopyalarını oluşturduğunuzdan emin olun. -C mac seçeneği, anahtarın osx ile uyumlu olmasını sağlar.


Bu cevap gerçekten asıl posterin sorusu değil.
hlin117

2
OS X kullanıcıları -c mac, OS X öncesi CRsadece yeni satırları dönüştürmek için kullanmamalıdır . Bu modu yalnızca Mac OS 9'a veya daha öncesine ait dosyalar için kullanmak istersiniz.
askewchan

2

TIMTOWTDI!

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

@GordonDavisson temel alınmıştır

Biri [noeol]...


2

Awk kullanabilirsiniz. Kayıt ayırıcıyı ( RS) olası tüm yeni satır karakteri veya karakterlerle eşleşen bir normal ifade olarak ayarlayın . Ve çıkış kayıt ayırıcısını ( ORS) unix tarzı yeni satır karakterine ayarlayın.

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

Benim için çalışan bu (MacOS, git diff^ M, vim'de düzenlendi)
Dorian

2

Linux'ta sed ile ^ M (ctrl-M) 'nix satırlarına (^ J) dönüştürmek kolaydır.

CLI'de böyle bir şey olacak, aslında metinde bir satır sonu olacak. Ancak, \ bu ^ J'yi sed'e iletir:

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

Bunu, yazarken ^ V (ctrl-V), ^ M (ctrl-M) ve \ (ters eğik çizgi) kullanarak elde edersiniz:

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

2
sed --expression='s/\r\n/\n/g'

Soru sed'den bahsettiği için, bunu başarmak için sed kullanmanın en basit yolu budur. İfadenin söylediği, tüm satır başı ve satır beslemenin yalnızca satır beslemeyle değiştirilmesidir. Windows'dan Unix'e geçtiğinizde ihtiyacınız olan şey budur. Çalıştığını doğruladım.


Hey John Paul - bu cevap silinmek üzere işaretlendi, bu yüzden benim için bir inceleme kuyruğuna geldi. Genel olarak, 8 yaşında böyle bir sorunuz olduğunda, 22 cevapla, cevabınızın mevcut diğer cevapların olmayacağı şekilde nasıl yararlı olduğunu açıklamak istersiniz.
zzxyz

0

Jonathan Leffler'ın Unix to DOS çözümünün bir uzantısı olarak, dosyanın geçerli satır sonlarından emin değilseniz güvenli bir şekilde DOS'a dönüştürmek için:

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

Bu, satırın CRLF'ye dönüştürülmeden önce CRLF'de bitmediğini kontrol eder.


0

Kabul edilen cevaba dayalı bir komut dosyası hazırladım, böylece sonunda ek bir dosyaya ihtiyaç duymadan ve daha sonra kaldırıp yeniden adlandırmadan doğrudan dönüştürebilirsiniz.

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

"file1.txt2" gibi bir dosyanız varsa, "file1.txt2" nin zaten mevcut olmadığından veya üzerine yazılacağından emin olun, bunu dosyayı depolamak için geçici bir yer olarak kullanıyorum.


0

Bash 4.2 ve daha yenisiyle, yalnızca bash yerleşiklerini kullanan son CR'yi şeritlemek için böyle bir şey kullanabilirsiniz:

if [[ "${str: -1}" == $'\r' ]]; then
    str="${str:: -1}"
fi

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.