Bir dosyanın üzerinde değişiklik yapmadan CRLF veya LF kullanıp kullanmadığı nasıl test edilir?


48

Bazı metin dosyalarının Linux modunda tutulmasını sağlayan bir komutu düzenli aralıklarla çalıştırmam gerekiyor . Ne yazık ki, dos2unixher zaman dosya ve klasörün zaman damgalarını bozan ve gereksiz yazmalara neden olan dosyayı değiştirir.

Yazdığım senaryo Bash'de, bu yüzden Bash'e dayalı cevapları tercih ediyorum.

Yanıtlar:


41

dos2unixFiltre olarak kullanabilir ve çıktısını orijinal dosyayla karşılaştırabilirsiniz:

dos2unix < myfile.txt | cmp -s - myfile.txt

2
Çok zeki ve kullanışlıdır, çünkü sadece ilk veya birkaç satırı değil tüm dosyayı test eder .
halloleo

2
Belki yerini alabilecek testtarafından myfile.txtbirlikte önlemek karışıklığa sizin örnekte iki kez /usr/bin/test.
Peterino

1
Not -sÇıktıyı görmek için bayrağı silmeniz gerekir . Man sayfalarından: -s, --quiet, --silent suppress all normal output
tobalr

24

Amaç sadece zaman damgasını etkilemekten kaçınmaksa, zaman damgasını aynı tutacak dos2unixbir -kveya --keepdateseçeneğine sahiptir. Geçici dosyayı oluşturmak ve yeniden adlandırmak için yine de bir yazı yazması gerekecek, ancak zaman damgalarınız bundan etkilenmeyecek.

Dosyanın herhangi bir şekilde değiştirilmesi kabul edilemez ise, bu cevabı aşağıdaki çözümü kullanabilirsiniz .

find . -not -type d -exec file "{}" ";" | grep CRLF

1
Kelimenin tam anlamıyla CRLF'yi 4, C, R, L ve F karakterleri olarak mı yazıyorsunuz?
bodacydo

7
Grep'in CR ve LF'yi de bu şekilde alabileceğini mi kastediyorsun?
bodacydo

@bodacydo Bağlandığı cevabında ve şimdi de Scott'ın BertS'in cevabını burada düzenlediği unix.stackexchange.com/a/79708/59699 .
dave_thompson_085

@ dave_thompson_085 Açıklama göremiyorum. Yalnızca CRLF'den bahseder, ancak ne olduğunu açıklamaz.
bodacydo

1
@bodacydo stackoverflow.com/questions/73833/... söylüyor find ... -exec file ... | grep CRLFDOS satır sonları bir dosyaya (yani bayt 0D 0A) için "Size böyle bir şey alacak: ./1/dos1.txt: ASCII text, with CRLF line terminators Bu gerçek bir dize CRLF içerir ve bu nedenle tarafından eşleştirilir görebileceğiniz gibi greparayan basit dize CRLF.
dave_thompson_085

22

Sen deneyebilirsiniz grepCRLF kodu, sekizli için:

grep -U $'\015' myfile.txt

veya altıgen:

grep -U $'\x0D' myfile.txt

Tabii ki, varsayım bunun bir metin dosyası olduğu.
mdpc

2
Bu grepkullanımı seviyorum çünkü dizindeki tüm bu dosyaları kolayca listeleyip grep -lU $'\x0D' *çıktısını almama izin veriyor xargs.
Melebius

arama modelinden önceki $ 'ın anlamı nedir? @don_crissti
fersarr



13

İlk yöntem ( grep):

Satır başı içeren satırları say:

[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos

Satır başı biten satırları say :

[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos

Bunlar tipik olarak eşdeğer olacaktır; Bir çizginin içinde (yani sonunda değil) bir taşıt dönüşü nadirdir.

Daha verimli:

grep -q $'\r' myfile.txt && echo dos

Bu daha verimli

  1. çünkü sayımı bir ASCII dizgisine dönüştürmeye ve daha sonra bu dizgiyi bir tamsayıya dönüştürmeye ve sıfıra dönüştürmeye gerek duymadığından ve
  2. çünkü grep -c, tüm dosyanın okunması gerekiyor, desenin tüm oluşumlarını saymak için, desenin grep -qilk oluşumunu görünce çıkabilirsiniz.

Notlar:

  • Yukarıdakiler boyunca, -Useçeneği eklemeniz gerekebilir (örneğin, -cUveya kullanın -qU), çünkü GNU grep, dosyanın bir metin dosyası olup olmadığını tahmin eder. Dosyanın metin olduğunu düşünüyorsa, $normal ifadelerin "doğru" çalışmasını sağlamak için satırların sonundaki satırbaşlarını dikkate almaz - normal ifade olsa bile \r$! Belirtme -U(veya --binary), bu tahmin çalışmasını geçersiz kılar; bu grep, dosyalara ikili olarak davranma ve verileri CR uçları bozulmadan, eşleşme mekanizmasına aktarmalarına neden olur.
  • Yapmayın grep … $'\r\n' myfile.txt, çünkü bir desen sınırlayıcı olarak grepdavranır \n. Tıpkı grep -E 'foo|'satırlar fooveya boş bir dize arar, satırlar veya boş bir dize grep $'\r\n'arar \rve her satır bir boş dize ile eşleşir.

İkinci yöntem ( file):

[[ $(file myfile.txt) =~ CRLF ]] && echo dos

çünkü fileşöyle bir şey rapor ediyor:

myfile.txt: UTF-8 Unicode text, with CRLF line terminators

Daha güvenli değişken:

[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos

nerede

Çıktısını kontrol etmenin file ingilizce olmayan bir yerel ayarda çalışmayabileceğini unutmayın.


1
Şahsen yanlış pozitif sayısını azaltmak için kullanacağım halde "$(echo -e '\r')"daha basitle değiştirebilirsiniz . $'\r'$'\r\n'
rici

@rici sistemimdeki grep $'\r\n'tüm dosyalar ile
eşleşiyor

@rici: iyi yakalamak. Cevabımı önerinize göre düzenledim. - depquid: Belki de Windows'tasınız? :-) rici'nin ipucu burada çalışıyor.
BertS

@depquid (ve BertS): Aslına bakarsan bence doğru çağrı, ikinci satır sonlarını tahmin etmeye çalışmaktan grep -U $'\r$'kaçınmaktır grep.
rici

Ayrıca, -qbir eşleşme bulunursa, bunun yerine -cek bir kontrol gerektiren sadece dönüş kodunu ayarlamak için kullanabilirsiniz . Şahsen ikinci çözümünüzü sevdim, ancak fileİngilizceye bağlı olmayan bir yerel bölgede kaprisli ve hevesli olmasına rağmen .
rici

11

kullanım cat -A

$ cat file
hello
hello

Şimdi, eğer bu dosya * NIX sistemlerinde yapılmış olsaydı,

$ cat -A file
hello$
hello$

Ancak bu dosya Windows'ta yapılmışsa,

$ cat -A file
hello^M$
hello

^Mtemsil eder CRve $temsil eder LF. Windows'un son satırı kaydetmediğine dikkat edin.CRLF

Bu, dosya içeriğini de değiştirmez.


En iyi ve en basit çözüm! daha fazla oy gerekiyor.
user648026

1
+1 Bugüne kadar en iyi cevap. Bağımlılık yok, karmaşık bash betiği yok. Sadece -Akedi için. Ancak bir ipucu, cat -A file | lesseğer dosya çok büyükse kullanmaktır. Eminim özellikle uzun bir dosya için dosya sonlarını kontrol etmek zor değildir. (Daha qaz bırakmak için basın )
Nicholas Pipitone

4

sizin için bir bash işlevi:

# return 0 (true) if first line ends in CR
isDosFile() {
    [[ $(head -1 "$1") == *$'\r' ]]  
}

Sonra gibi şeyler yapabilirsiniz

streamFile () {
    if isDosFile /tmp/foo.txt; then
        sed 's/\r$//' "$1"
    else
        cat "$1"
    fi
}

streamFile /tmp/foo.txt | process_lines_without_CR

3
Sen kullanmak zorunda değilsiniz isDosFile()sizin örnekte: streamFile() { sed 's/\r$//' "$1" ; }.

1
Bunun en şık çözüm olduğunu düşünüyorum; tüm dosyayı okumaz, sadece ilk satırdır.
Adam Ryczkowski

4

Bir dosyada DOS / Windows tarzı CR-LF satır sonları varsa, o zaman Unix tabanlı bir araç kullanarak bakarsanız, her satırın sonunda CR ('\ r') karakterleri görürsünüz.

Bu komut:

grep -l '^M$' filename

yazdırılacaktır filenamedosyası Windows tarzı satır sonları ile bir veya birden fazla satır içeriyorsa ve bunları yapmazsa hiçbir şey yazdırılır. Bunun dışında ^M, genellikle yazarak terminali girilen bir hazır taşıyıcı dönüş karakteri olmak zorunda Ctrl+ Vardından Enter (veya Ctrl+ Vve sonra Ctrl+ M). Bash kabuğu, değişmez bir satır başı $'\r'( burada belgelenen ) gibi yazmanızı sağlar , böylece:

grep -l $'\r$' filename

Diğer kabuklar da benzer bir özellik sağlayabilir.

Bunun yerine başka bir araç kullanabilirsiniz:

awk '/\r$/ { exit(1) }' filename

Bu durumuyla çıkılacak 1(ayar $?için 1dosya herhangi bir Windows tarzı satır sonları içeriyorsa) ve durumuyla 0bir kabuk içinde yararlı hale yapmazsa ifaçıklamada (eksikliğini not [parantez ]):

if awk '/\r$/ { exit(1) }' filename ; then
    echo filename has Unix-style line endings
else
    echo filename has at least one Windows-style line ending
fi

Bir dosya, Unix ve Windows tarzı çizgi sonlarının bir karışımını içerebilir. Sana sahip dosyaları algılamak istiyorum burada tahmin ediyorum herhangi Windows stili satır sonları.


1
$'\r'Bu sorunun diğer cevaplarında da belirtildiği gibi , bash (ve bazı diğer kabukları) komut satırındaki satırbaşını kodlayarak yazabilirsiniz .
Scott,

2

Kullanım file:

$ file README.md
README.md: ASCII text, with CRLF line terminators

$ dos2unix README.md
dos2unix: converting file README.md to Unix format...

$ file README.md
README.md: ASCII text

Bu fikir daha önceki iki cevapta çok daha ayrıntılı olarak ele alınmıştır.
G-Man

1

Kullanıyorum

cat -v filename.txt | diff - filename.txt

bu iş gibi görünüyor. Çıktıyı okumaktan biraz daha kolay buluyorum

dos2unix < filename.txt | diff - filename.txt

dos2unixBazı nedenlerden dolayı kuramazsanız da kullanışlıdır .

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.