CRLF ve LF satır sonları: gerçekte ne bozulur
CRLF ile LF arasındaki fark tek bir bayt. LF tek bir \n (0x0A) karakteridir ve Linux ile macOS’ta satırları sonlandırır. CRLF ise iki bayttır: \r\n (0x0D 0x0A). Windows’ta satırlar bununla biter.
Şimdi çoğu yazının yanlış anlattığı kısım. Satır sonları CRLF olan bir shell betiği genellikle başarısız olmaz. Çalışır, beklediğiniz çıktıyı basar ve 0 ile çıkar. Bozulan şey, bir değişkenin içinde duran değerdir: atama sondaki \r baytını olduğu gibi saklamıştır ve kimse bundan şikâyet etmemiştir.
Ölçümlerden dört biçim çıktı; fark edilmesi en zor olandan en kolayına doğru:
- Sessiz başarı. Çıktı doğru görünür ve çıkış kodu 0’dır, bir değişken ise görünmez bir
\rtaşır. - Hiçbir şeyi değiştirmeyen hata. Boş satırda
: command not foundbasılır, betik sonuna kadar çalışır ve 0 ile çıkar. - Sözdizimi hatası.
if,forve fonksiyon tanımları bozulur, çıkış kodu 2. bad interpreter. Shebang satırı\rtaşır, çıkış kodu 126.
Her şeyden önce file yourfile komutunu çalıştırın. Tek satırlık çıktı, CRLF ile LF’nin hangi tarafında olduğunuzu söyler.
Aşağıdaki her şey macOS (Darwin arm64) üzerinde bash 3.2.57(1)-release, zsh 5.9, dash, git 2.55.0, node v26.7.0 ve Python 3.14.6 ile ölçüldü; ayrıca
docker run --rm bash:5üzerinden Linux’ta çapraz doğrulandı, yani GNU bash 5.3.15(1)-release (aarch64-unknown-linux-musl) üzerinde.
1. CRLF, LF ve CR: baytlar gerçekte ne
CRLF, carriage return line feed’in kısaltmasıdır ve ad harfi harfine doğrudur: birbirine yapıştırılmış iki karakter.
| Ad | Kaçış dizisi | Bayt |
|---|---|---|
| Carriage return | \r | 0x0D |
| Line feed | \n | 0x0A |
| CRLF | \r\n | 0x0D 0x0A |
Hangi platform hangisini yazar:
| Platform | Satır sonu |
|---|---|
| Windows | CRLF (\r\n) |
| Linux, güncel macOS | LF (\n) |
| Mac Classic, OS 9 ve öncesi | tek başına CR (\r) |
Adlar mekanik kökenli. Bir teletype makinesinde carriage return yazıcı kafasını sol kenara geri götürürdü, line feed ise kâğıdı bir satır yukarı sarardı. Windows iki hareketi de iki bayt olarak korudu; Unix birinin yettiğine karar verdi. Tek başına CR eski dışa aktarımlarda hâlâ karşınıza çıkar ve bunlarla dolu bir dosya çoğu Unix aracının gözüne tek bir devasa satır gibi görünür.
Elinizdekini tek bir komut söyler
file baytları okur ve sonlandırıcının adını verir:
$ file d1.txt
d1.txt: ASCII text, with CRLF line terminators
$ file d2.txt
d2.txt: ASCII text ← no suffix means pure LF
$ file d3.txt
d3.txt: ASCII text, with CRLF, LF line terminators ← mixed, file lists both
Üçüncü durum öğrenmeye değer. Satır sonları karışık olan bir dosya, farklı ayarlarla çalışan iki aracın sırayla o dosyaya yazdığı anlamına gelir: bir editör LF ile kaydetmiştir, bir betik CRLF eklemiştir, bir merge iki sürümü birbirine dikmiştir. od -c bu bölünmeyi bayt bayt gösterir:
$ od -c d3.txt
0000000 a \r \n b \n
0000005
Satır sonları bayt katmanında, karakter kodlamasının hemen yanında yaşar; bir üst katmanda ne olduğunu UTF-8 ve UTF-16 kodlama rehberi anlatıyor.
2. Dört hata biçimi: sessiz başarıdan çıkış kodu 126’ya
Aynı \r\n dosyası, satırın içeriğine göre beş farklı sonuç veriyor:
| Betik içeriği | Gerçekte ne olur | Çıkış |
|---|---|---|
echo hello ve diğer basit komutlar | Sessiz başarı, çıktı doğru | 0 |
X=abc ataması | Sessiz başarı, ama değerin sonunda \r var | 0 |
Boş satırlar, sonu \ ile biten devam satırları | : command not found, betik sonuna kadar çalışmayı sürdürür | 0 |
if/fi, for/do/done, f() { | syntax error near unexpected token | 2 |
\r içeren shebang satırı | bad interpreter: No such file or directory | 126 |
Bu sayfa ilk iki satır yüzünden var. “CRLF, command not found hatasına yol açar” cümlesi her yerde tekrarlanıyor ama olan bu değil. Basit komutlar hiç şikâyet etmiyor.
Asıl tehlikeli olan sessiz başarı
$ printf 'echo hello\r\necho world\r\n' > win.sh && bash win.sh
hello
world
[exit=0]
İki satır girdi, iki satır çıktı, çıkış kodu 0. Hata ayıklanacak bir şey yok; günlükte arayacağınız bir dize de yok. Aynı betiğe bir karşılaştırma ekleyin, sonuç değişir:
$ printf 'V=1.2.3\r\ntest "$V" = "1.2.3" && echo MATCH || echo NO-MATCH\r\n' > v.sh
$ bash v.sh
NO-MATCH
[exit=0]
$V değişkeninde 1.2.3 değil, 1.2.3\r var. macOS ve Linux’ta sonuç birebir aynı. Sürüm kontrolleri, if [ "$ENV" = "prod" ] karşılaştırmaları, dosyadan okunan özellik bayrakları: hepsi sessiz sedasız yanlış dala girer ve çıkış kodu yine 0 olur. CI içinde bulunması en zor satır sonu hatası budur, çünkü derleme yeşildir ve günlük tertemizdir.
Hiçbir şeyi durdurmayan hata
Bir CRLF dosyasının içinde boş satır, yalnızca \r içeren bir satır demektir ve shell bunu çalıştırılacak bir komut sayar. Komut başarısız olur, bir mesaj basar, betik bir sonraki satıra geçer ve 0 ile biter. Mesajın tam metni kullandığınız shell’e göre değişir.
Sonu ters eğik çizgiyle biten devam satırları da aynı şekilde bozulur. \r, ters eğik çizgi ile satır sonu arasına girer; böylece devam satırı devam olmaktan çıkar ve sonraki satır kendi başına çalışır.
Sözdizimi hataları: fi neden fi değil
c_if.sh: line 5: syntax error: unexpected end of file
[exit=2]
Linux’taki bash 5.3.15 aynı dosya hakkında daha fazlasını söylüyor:
i.sh: line 5: syntax error: unexpected end of file from `if' command on line 2
Döngüler ve fonksiyon tanımları ise bunun yerine 1. satırda patlar:
c_for.sh: line 1: syntax error near unexpected token `do'
c_for.sh: line 1: `for i in 1 2; do'
c_func.sh: line 1: syntax error near unexpected token `{'
c_func.sh: line 1: `f() {'
Bu hata sınıfının tamamını tek bir mekanizma açıklıyor. Bash kapanış sözcüğünü fi olarak değil, fi\r olarak okur. fi\r ise fi anahtar sözcüğü değildir; dolayısıyla if bloğu hiç kapanmaz ve bash dosya bitene kadar okumayı sürdürür. Hatanın bozuk satırı değil de son satırı göstermesinin nedeni bu.
bad interpreter ve çıkış kodu 126
$ ./s.sh
bash: ./s.sh: /bin/bash^M: bad interpreter: No such file or directory
[exit=126]
macOS ve Linux aynı metni basar, ikisi de 126 ile çıkar. Mesajdaki yolu okuyun: /bin/bash^M. Çekirdek, #! işaretinden satır sonuna kadar olan her şeyi yorumlayıcının yolu sayar ve \r de bu yolun bir parçasıdır. Böyle bir dosya bulunmadığı için exec, betiğinizin tek bir satırı bile çalışmadan başarısız olur.
Çıkış kodu 126 aynı zamanda “bulundu ama çalıştırılabilir değil” durumunu da kapsar; yani başlamayı reddeden her betik doğrudan bir satır sonu sorunu değildir. Dosya izinleri de aynı aileden hatalar üretir. İkisini birbirinden ayıran şey, yolun içindeki ^M.
\r baytını neden hiç görmezsiniz
Çıktıyı okumak işe yaramaz, çünkü bu bayt ne bakacağınız ne de seçebileceğiniz bir iz bırakır. Onu görünür kılmanız gerekir:
$ bash d.sh # script: HOST=example.com / echo "connecting to $HOST:8080"
connecting to example.com:8080 ← what you get
$ bash d.sh | cat -v
connecting to example.com^M:8080^M ← what is actually there
$ bash d.sh | od -c
0000000 c o n n e c t i n g t o e x
0000020 a m p l e . c o m \r : 8 0 8 0 \r
0000040 \n
Normal çıktıda görünmeyen iki \r baytı var ve ikisi de birazdan sunucu adı olarak kullanılacak bir karakter dizisinin içinde duruyor. Bazen bu bayt bir argümanın içine sızar ve suç ilgisiz bir aracın üstünde kalır:
$ bash v.sh # the script pipes through: ... | head -2
head: illegal line count -- 2\r
head doğru davranıyor. Betik ona 2\r verdi. Alıntılanan değerin içinde başıboş bir \r gördüğünüz her hata mesajı, başkasının adını takmış bu hatadır.
3. Hata mesajınız neden internetteki mesaja hiç benzemiyor
Tek bir dosya (printf 'echo a\r\n\r\necho b\r\n', 2. satırı yalnızca \r içeren boş bir satır) dört ayrı shell altında çalıştırıldı:
| Shell | Sürüm | Tam mesaj |
|---|---|---|
| bash (macOS ile gelen) | 3.2.57(1)-release | s_blank.sh: line 2: : command not found |
| bash (yaygın Linux dağıtımları) | 5.3.15(1)-release | t.sh: line 2: $'\r': command not found |
| zsh | 5.9 | s_blank.sh:2: command not found: ^M |
| dash | — | s_blank.sh: 2: : not found |
Arama sonuçlarının neredeyse tamamı ikinci satırı alıntılıyor. Bash 4 ve 5, basılamayan karakterleri ANSI-C alıntılamasıyla yazar; bu da carriage return karakterini $'\r' haline getirir. macOS ile gelen bash 3.2’de bu davranış yok; elinizde iki nokta üst üste, bir boşluk ve aralarında hiçbir şey kalıyor. zsh ^M basar. dash ise “command” sözcüğünü tamamen atar.
Tek bir arıza, dört mesaj. Hatanızı olduğu gibi arama kutusuna yapıştırıp işe yarar bir şey bulamadıysanız sebebi bu. Çıplak : command not found de meşhur olanla aynı hatadır.
4. Git: core.autocrlf deponuza gerçekte ne kaydeder
git autocrlf anlatımlarının çoğu tanımlarda durur. Daha çok işe yarayan iki soru var: commit’e ne giriyor ve takım arkadaşlarınız checkout yaptığında ellerine ne geçiyor? Depoya kaydedilen blob için git cat-file -p HEAD:f.txt, çalışma kopyası için rm f.txt && git checkout -- f.txt ile ölçüldü:
core.autocrlf | Kaynak dosya | Depodaki blob | Checkout sonrası çalışma kopyası |
|---|---|---|---|
true | CRLF | LF | CRLF |
true | LF | LF | CRLF |
input | CRLF | LF | LF |
input | LF | LF | LF |
false | CRLF | CRLF | CRLF |
false | LF | LF | LF |
Bu tablodan üç sonuç çıkıyor:
truedainputda depoda LF olmasını garanti eder. Tek fark checkout’ta:truedosyayı CRLF’ye geri çevirir,inputdosyaya dokunmaz.- Bir commit’in içine CRLF sokan tek değer
false. Carriage return baytlarını depoya kimin soktuğu sorulduğunda cevap bu satırdır. - Sürpriz ikinci satırda.
truealtında, diskte LF olan bir dosya checkout’tan CRLF olarak geri döner.
Git bu yeniden yazmayı gerçekleşmeden önce duyurur, iki biçimden biriyle:
warning: in the working copy of 'f.txt', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'f.txt', CRLF will be replaced by LF the next time Git touches it
“Hiçbir şeyi değiştirmedim ama git bütün dosya değişti diyor”
Yine ikinci satır. git config core.autocrlf true ayarıyla checkout, çalışma dizinindeki LF dosyalarını CRLF olarak yeniden yazar. Artık her satır blob’dan bir bayt farklıdır; git diff bütün satırları değişmiş sayar ve pull request’te kimsenin dokunmadığı bir dosya baştan sona yeniden yazılmış görünür. Bunu yapan, checkout filtresidir.
Aynanın öteki yüzü de aynı gürültüyü üretir: false kullanan bir takım arkadaşınız CRLF commit’ler, siz input kullanırsınız ve hiç açmadığınız dosyalar sizin diff’inizde belirir.
5. Takım düzeyindeki cevap: .gitattributes
core.autocrlf tek bir makinedeki bir ayardır ve başka kimse onu göremez. .gitattributes ise deponun içindeki bir dosyadır, dolayısıyla her klonla birlikte yolculuk eder. İkisi çeliştiğinde kazanan öznitelikler olur. Dört biçimin dördü de test edildi:
.gitattributes | core.autocrlf | Kaynak | Blob | Checkout sonrası | Kazanan |
|---|---|---|---|---|---|
* text=auto | false | CRLF | LF | LF | öznitelikler |
* text eol=crlf | input | LF | LF | CRLF | öznitelikler |
* -text | true | CRLF | CRLF | CRLF | öznitelikler |
* text eol=lf | true | CRLF | LF | LF | öznitelikler |
Üçüncü satır aklınızda kalsın: -text dönüşümü tamamen kapatır ve buna rağmen core.autocrlf=true ayarını yener. Baytlarının hiç dokunulmadan kalması gereken dosyaları böyle korursunuz.
Kopyalayabileceğiniz bir .gitattributes
* text=auto
*.sh text eol=lf
*.bash text eol=lf
Makefile text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.png -text
*.jpg -text
*.pdf -text
*.zip -text
text=auto, Git’in metin olarak algıladığı her şeyi depoda LF’ye normalleştirir. Açıkça yazılmış eol=lf satırları, kim yazarsa yazsın LF olmak zorunda olan dosyaları kapsar; çünkü CRLF’li bir .sh dosyası, patlamayı bekleyen bir çıkış kodu 126 demektir. Windows betik türleri simetrik nedenle eol=crlf alır, ikili dosya kalıpları ise hiçbir dönüşüm olmasın diye -text alır.
core.safecrlf ve core.eol
core.autocrlf ile birlikte anılan, ama bambaşka bir işi gören iki ayar:
core.safecrlfbir dönüştürücü değil, bir korumadır. Bir dönüşüm gidiş-dönüşte aslına geri dönmeyecekse (karışık bir dosyada olduğu gibi, normalleştirme bilgi kaybettiriyorsa)trueişlemi reddeder,warnise uyarı vererek geçirir. Hangi baytların saklandığını asla değiştirmez; yalnızca kayıplı dönüşümlerin sessizce geçmesine izin vermez.core.eol,core.autocrlfdeğerifalseikentextolarak işaretlenmiş dosyalar için Git’in çalışma dizinine hangi satır sonunu yazacağını seçer. Alabileceği değerlerlf,crlfvenative.core.autocrlfonu ezer; autocrlf hâlâ açıkkencore.eolayarlamanın hiçbir şey yapmamış gibi görünmesinin sebebi de bu.
.gitattributes değiştirmek, çoktan commit’lenmiş dosyaları düzeltmez
Öznitelikler, Git bir dosyayı yazarken ya da okurken devreye girer; dolayısıyla mevcut içerik, bir şey onu yeniden yazana kadar olduğu gibi kalır. O geçişi kendiniz zorlayın:
$ git add --renormalize .
$ git commit -m "Normalize line endings"
Devasa bir diff bekleyin; zaten amaç da bu. İşi ayrı bir dalda yürütün, tek bir commit’te birleştirin ve o commit depoya girmeden önce herkese haber verin.
6. CRLF’yi LF’ye çevirmek, sonra geri almak
Dört yol; dördünün de Darwin üzerinde \r baytını temizlediği doğrulandı:
| Komut | Sonuç |
|---|---|
tr -d '\r' < f > f.out | çalışır |
perl -pi -e 's/\r\n/\n/g' f | çalışır |
sed -i '' -e 's/\r$//' f (BSD biçimi) | çalışır |
sed -i -e 's/\r$//' f (GNU biçimi, macOS’ta çalıştırıldığında) | çalışır, ama arkasında çöp bir dosya bırakır |
macOS’ta GNU sed -i tuzağı
BSD sed, -i seçeneğinin ardından bir yedek dosya soneki bekler. Linux için yazılmış bir anlatımı olduğu gibi kopyalarsanız BSD sed, -e bayrağını istenen sonek sanıp yutar. Düzenlemeniz yine de gerçekleşir, ama yanında şu da olur:
a5.txt
a5.txt-e
a5.txt-e bir yedek kopya; sed, -e bayrağını sizin istediğiniz sonek olarak okuduğu için oluştu. Doğru macOS biçimi, açıkça boş bir karakter dizisi geçirir: sed -i '' -e 's/\r$//' f. İçinde -e uzantılı dosyalar commit’lenmiş bir depo, birinin Mac’te bir GNU tek satırlığı çalıştırdığı bir depodur.
macOS’ta dos2unix yok
Hiç dokunulmamış bir macOS sisteminde command -v dos2unix hiçbir şey döndürmez; ikili dosya brew install dos2unix ile gelir. İnternette en çok kopyalanan cevabın, pek çok geliştiricinin başında oturduğu makinede işe yaramamasının sebebi bu. tr -d '\r' hiçbir kurulum istemez ve aynı işi görür.
Ters yönde unix2dos da aynı erişilebilirlik sorununu taşır; yerine sed -e 's/$/\r/' iş görür.
Bir dosya temiz LF’ye döndüğünde onu yeniden bir satır listesi gibi ele almak güvenlidir. Satırları bütün birer karakter dizisi olarak karşılaştıran her şey için bu önemli: metin satırlarını sırala ve yinelenen satırları kaldır araçlarının ikisi de value\r ile value satırlarını iki ayrı satır olarak okur; tek bir başıboş carriage return, yineleme temizliğini sessizce boşa çıkarır.
Editörünüzde
VS Code, açık dosyanın satır sonunu sağ alttaki durum çubuğunda CRLF ya da LF olarak gösterir; üstüne tıklamak dosyayı diğerine çevirir. files.eol ayarı yeni dosyaların varsayılanını belirler ve bunu çalışma alanı bazında ayarlamak karma bir takımı tutarlı tutar. Diğer editörler aynı iki denetimi başka adlarla sunar. Gözden kaçan nokta şu: dosya bazındaki gösterge ile varsayılan ayar birbirinden ayrıdır, birini değiştirmek diğerine dokunmaz.
7. Satır sonlarını kodun içinde ele almak
Tek bir dosya (line1\r\nline2\r\n) yedi ayrı giriş noktasından okundu:
| Giriş noktası | Elinize geçen | \r |
|---|---|---|
Node fs.readFileSync(f,"utf8") | "line1\r\nline2\r\n" | korunur |
Node, aynı değer + .split("\n") | ["line1\r","line2\r",""] | her satırda korunur |
Node readline, crlfDelay:Infinity ile | ["line1","line2"] | temizlenir |
Python open(f), varsayılan kip | 'line1\nline2\n' | dönüştürülür |
Python open(f).readlines() | ['line1\n','line2\n'] | dönüştürülür |
Python open(f, newline="") | 'line1\r\nline2\r\n' | korunur |
Python open(f,"rb") | b'line1\r\nline2\r\n' | korunur |
Bu tablo tanıdık bir hata bildirimini kapatıyor: Python’da çalışıyor, Node’da bozuluyor. Python’un varsayılan metin kipi universal newlines uygular ve \r\n dizisini siz görmeden önce \n haline çevirir. Node ise baytları olduğu gibi verir. İkisi de yanlış değil, ama aynı dosyayı okudukları anda birbirinden ayrılıyorlar.
rstrip("\n") çağrısı \r baytını geride bırakır
original: 'line1\r\n' | rstrip("\n"): 'line1\r' | strip(): 'line1'
rstrip("\n") tam olarak listelediğiniz karakterleri siler ve \r o listede yoktu. Sonuç, eşleşmesi gereken her şeyle eşitsiz çıkar; “temizledim ama hâlâ eşit değil” cümlesinin dürüst cevabı da bu. strip() kullanın ya da rstrip() fonksiyonunu argümansız çağırın; sondaki bütün boşluk karakterleri, carriage return dahil, gider.
İki platformda da satırları güvenle bölmek
JavaScript’te iki satır sonunu da tolere eden bir kalıpla bölün: text.split(/\r?\n/). Python’da ya varsayılan metin kipinde kalıp işi universal newlines mekanizmasına bırakın ya da splitlines() çağırın; bu fonksiyon \r\n, \n ve tek başına \r ile başa çıkar.
İşin öteki yarısı yazma. Node kendisine verdiğiniz baytları yazar; o yüzden karakter dizilerini \n ile kurun ve diske ne ineceğine .gitattributes karar versin. Python’da open(path, "w"), siz newline="" geçirmediğiniz sürece \n karakterini platformun satır sonuna çevirir; CSV yazıcılarının tam da bu bayrağı istemesinin sebebi bu.
Satır sonundaki bir carriage return ile dosya başındaki bir byte-order mark, aynı hata sınıfının iki ucudur: kopyala-yapıştırdan sağ çıkan ve bir eşitlik kontrolünü bozan görünmez bir bayt. Öbür ucu UTF-8 BOM sorun giderme rehberi anlatıyor.
8. Satır sonlarının canınızı yaktığı diğer yerler
CSV, CRLF’nin kusur değil doğru seçim olduğu ender yerlerden biri: RFC 4180 onu kayıt ayırıcı olarak şart koşar. Yalnızca LF girdisi için yazılmış ayrıştırıcılar her satırın son alanında bir \r bırakır; CSV’den JSON’a dönüşümden çıkan değerler doğru görünüp karşılaştırmada tutmuyorsa önce o bayta bakın.
Docker’da, imajın içine kopyalanmış ve satır sonları CRLF olan bir .sh dosyası dördüncü hata biçiminin ta kendisidir. COPY baytları korur, shebang \r baytını taşımayı sürdürür ve konteyner 126 ile çıkar. .gitattributes içindeki tek bir *.sh text eol=lf satırı bu hata sınıfının tamamını önler.
Bir pull request’te, görünür hiçbir düzenleme olmadan baştan sona değişmiş görünen bir dosya, 4. bölümdeki mekanizmanın kod incelemesine yansımış halidir. İki sürümü metin karşılaştırma aracıyla kıyaslamak bunu saniyeler içinde doğrular; sonucu nasıl okuyacağınızı da metin karşılaştırma rehberi adım adım anlatıyor.
file komutu ASCII text, with CRLF, LF line terminators diyorsa aynı dosyaya farklı ayarlarla çalışan iki yazıcı yazmış demektir. Yalnızca düzenlemiş olduğunuz satırları değil, dosyanın tamamını normalleştirin; yoksa bir sonraki diff de en az bu kadar gürültülü olur.
SSS
CRLF ile LF arasındaki fark nedir?
CRLF iki bayttır: \r\n (0x0D 0x0A). LF tek bayttır: \n (0x0A). Windows CRLF yazar, Linux ve macOS LF yazar; ikisi de satırın sonunu işaretler. Metin bir editörde birebir aynı görünür; fark yalnızca baytlarda, karakter dizisi karşılaştırmalarında ve diff’lerde ortaya çıkar.
Betiğimin satır sonları CRLF, neden hiç hata almıyorum?
Çünkü basit komutlar fazladan baytı sorunsuz atlatır. Sonunda \r olan bir echo hello çalışır ve 0 ile çıkar. Hatalar yalnızca ayrıştırıcının önemsediği yerlerde görünür: boş bir satır, fi gibi bir anahtar sözcük ya da shebang. Asıl tehlikeli durum atamalardır, çünkü başarılı olurlar ve \r baytını değişkenin içinde saklarlar.
$'\r': command not found ne demek ve ben bu mesajı neden görmüyorum?
Shell’in, yalnızca bir carriage return içeren bir satırı çalıştırmaya kalktığı anlamına gelir. Bash 4 ve 5 bu karakteri ANSI-C alıntılamasıyla basar, ortaya $'\r' çıkar. macOS ile gelen bash 3.2 iki nokta üst üste arasına hiçbir şey basmaz, zsh ise onun yerine ^M basar. Tek arıza, üç ayrı mesaj.
core.autocrlf değeri true mu, input mu, false mu olmalı?
Linux ve macOS’ta input, Windows’ta true kullanın; ikisi yerine .gitattributes tercih edin. Ölçümlere göre true da input da depoda LF saklar ve bir commit’in içine CRLF girmesine yalnızca false izin verir. true ayrıca checkout sırasında çalışma kopyanızdaki LF dosyalarını CRLF olarak yeniden yazar.
.gitattributes ile core.autocrlf çelişirse hangisi kazanır?
.gitattributes kazanır. Test edilen dört biçim de (* text=auto, * text eol=crlf, * -text ve * text eol=lf) yerel core.autocrlf değerini ezdi. Onu kullanmanın gerekçesi de bu: öznitelikler commit’lenir ve herkes için geçerlidir, core.autocrlf ise göremediğiniz ve dayatamadığınız, makineye özel bir ayardır.
Bir dosyanın CRLF mi LF mi kullandığını nasıl anlarım?
file yourfile komutunu çalıştırın. CRLF için ASCII text, with CRLF line terminators, saf LF için hiçbir ek olmadan ASCII text, karışık bir dosya için ise with CRLF, LF line terminators basılır. Bayt düzeyinde kesinlik isterseniz od -c çalıştırın ve her \n baytından önce bir \r duruyor mu diye bakın.
CRLF gerçekten ne zaman kullanılmalı?
Bir biçim ya da protokol bunu şart koştuğunda. RFC 4180, CSV için kayıt ayırıcı olarak CRLF’yi tanımlar; HTTP başlıkları ile SMTP de hat üzerinde aynı ayırıcıyı kullanır. Windows batch ve PowerShell dosyaları da CRLF ile daha güvenlidir. Bunların dışında her yerde LF: kaynak kodu, shell betikleri, yapılandırma dosyaları.