Konwertowanie tekstu z Windows na format Linux
Zarządzanie konwersjami końcówek linii między platformami
Niespójności końcówek wierszy między systemami Windows a Linux (https://www.glukhov.org/pl/post/2025/11/conversing-windows-text-to-linux/ “Niespójności końcówek wierszy między systemami Windows a Linux”) powodują problemy z formatowaniem, ostrzeżenia Git i awarie skryptów. Ta kompleksowa przewodnik obejmuje wykrywanie, konwersję i strategie zapobiegania.
To piękne zdjęcie zostało wygenerowane przez model AI Flux 1 dev.
Zrozumienie różnic w końcówkach wierszy
Systemy operacyjne korzystają z różnych konwencji do oznaczania końca wiersza w plikach tekstowych, tworząc wyzwania kompatybilności w rozwijaniu aplikacji międzyplatformowych:
- Windows: Znak powrotu karetki + znak nowego wiersza (
\r\nlub CRLF, heks0D 0A) - Linux/Unix: Tylko znak nowego wiersza (
\nlub LF, heks0A) - Klasyczny system Mac OS: Tylko znak powrotu karetki (
\rlub CR, heks0D)
Te historyczne różnice wynikają z mechaniki maszyn do pisania. Windows dziedziczy konwencję CRLF z DOS, który utrzymywał kompatybilność z maszynami telegraficznymi wymagającymi zarówno powrotu karetki (przejście do początku wiersza), jak i zaawansowania papieru.
Typowe problemy spowodowane niespójnościami końcówek wierszy
1. Awarie wykonywania skryptów
Skrypty Bash z końcówkami wierszy z Windowsa zawierają niejasne błędy:
bash: ./script.sh: /bin/bash^M: zły interpreter: Brak takiego pliku ani katalogu
Znak ^M (powrót karetki) staje się częścią linii shebang, powodując niepowodzenie wyszukiwania interpretera.
2. Ostrzeżenia Git i szumy różnic
Podczas commitowania plików z Windowsa do Gita na Linuxie zobaczysz:
warning: CRLF zostanie zastąpiony przez LF w file.txt.
Plik będzie miał oryginalne końcówki wierszy w Twoim katalogu roboczym
Różnice Git mogą pokazywać całe pliki jako zmienione, kiedy tylko końcówki wierszy są inne, ukrywając rzeczywiste zmiany kodu.
3. Wizualne artefakty w edytorach
Edytory tekstowe w Linuxie, które nie automatycznie wykrywają końcówek wierszy, wyświetlają znaki ^M na końcu wierszy, co utrudnia czytanie i edytowanie plików. Jest to szczególnie problematyczne w plikach markdown w Hugo, gdzie może to zniszczyć analizę frontmatter.
4. Problemy przetwarzania danych
Skrypty przetwarzające pliki tekstowe mogą zawierać znaki powrotu karetki w wyodrębnionych danych, co powoduje błędy porównania i nieoczekiwane zachowanie w przepływach danych.
Wykrywanie końcówek wierszy z Windowsa
Przed konwersją plików należy zidentyfikować, które wymagają konwersji, aby uniknąć zbędnych modyfikacji.
Metoda 1: Użycie polecenia file
Najbardziej niezawodna metoda wykrywania:
file content/post/my-post/index.md
Przykładowe wyniki:
# Windows line endings:
index.md: UTF-8 Unicode text, with CRLF line terminators
# Linux line endings:
index.md: UTF-8 Unicode text
# Mixed line endings (problematic):
index.md: UTF-8 Unicode text, with CRLF, LF line terminators
Metoda 2: Wizualna inspekcja z użyciem cat
Wyświetlanie znaków kontrolnych:
cat -A filename.txt
Pliki Windowsowe pokazują ^M$ na końcu wierszy, podczas gdy pliki Linuxowe pokazują tylko $.
Metoda 3: Użycie grep
Wyszukiwanie znaków powrotu karetki:
grep -r $'\r' content/post/2025/11/
To identyfikuje wszystkie pliki zawierające CRLF w określonym katalogu.
Metoda 4: Analiza hexdump
Dla szczegółowej analizy na poziomie bajtów:
hexdump -C filename.txt | head -n 20
Szukaj sekwencji 0d 0a (CRLF) w przeciwieństwie do 0a (LF).
Konwersja z formatu Windows do Linux
Wiele narzędzi oferuje niezawodną konwersję z różnymi kompromisami w zakresie dostępności, funkcji i wydajności.
Rozwiązanie 1: dos2unix (Zalecane)
Najbardziej wydajne i bogate w funkcje rozwiązanie, specjalnie zaprojektowane do konwersji końcówek wierszy.
Instalacja
# Ubuntu/Debian
sudo apt install dos2unix
# Red Hat/CentOS/Fedora
sudo yum install dos2unix
# macOS (Homebrew)
brew install dos2unix
# Arch Linux
sudo pacman -S dos2unix
Podstawowe użycie
# Konwersja pojedynczego pliku (modyfikuje w miejscu)
dos2unix filename.txt
# Konwersja z kopią zapasową (tworzy plik .bak)
dos2unix -b filename.txt
# Konwersja wielu plików
dos2unix file1.txt file2.txt file3.txt
# Konwersja z użyciem wieloznaczników
dos2unix *.txt
dos2unix content/post/2025/11/*/index.md
Zaawansowane opcje
# Symulacja działania (podgląd bez modyfikacji)
dos2unix --dry-run filename.txt
# Zachowanie daty modyfikacji
dos2unix -k filename.txt
# Konwersja tylko jeśli końcówki wierszy są inne
dos2unix -f filename.txt
# Konwersja rekurencyjna
find . -name "*.md" -exec dos2unix {} \;
# Konwersja wszystkich plików markdown w drzewie katalogów
find content/post -type f -name "*.md" -exec dos2unix {} \;
Partia przetwarzania postów w Hugo:
# Konwersja wszystkich plików index.md w 2025 postach
dos2unix content/post/2025/**/index.md
# Konwersja wszystkich plików markdown z wyjątkiem określonych katalogów
find content/post -name "*.md" ! -path "*/drafts/*" -exec dos2unix {} \;
Rozwiązanie 2: Polecenie sed
Dostępne na wszystkich systemach Unix bez dodatkowej instalacji, choć mniej wydajne dla dużych partii.
# Konwersja pojedynczego pliku
sed -i 's/\r$//' filename.txt
# Konwersja wielu plików z pętlą
for file in content/post/2025/11/*/index.md; do
sed -i 's/\r$//' "$file"
done
# Konwersja z kopią zapasową
sed -i.bak 's/\r$//' filename.txt
# Rekurencyjna z find
find . -name "*.txt" -exec sed -i 's/\r$//' {} \;
Ważne uwagi
sed -imodyfikuje pliki w miejscu- Na macOS, użyj
sed -i '' 's/\r$//' filename.txt - Tworzy tymczasowe pliki podczas przetwarzania
- Wolniejsze niż dos2unix dla dużych zbiorów plików
Rozwiązanie 3: Polecenie tr
Podejście oparte na przesyłaniu, przydatne w przepływach przetwarzania danych:
# Podstawowa konwersja (wymaga przekierowania wyjścia)
tr -d '\r' < input.txt > output.txt
# Przetwarzanie i konwersja w przepływie
cat input.txt | tr -d '\r' | process_data.sh
# Nie można modyfikować w miejscu - użyj pliku tymczasowego
tr -d '\r' < input.txt > temp.txt && mv temp.txt input.txt
Zalety
- Dostępne na wszystkich systemach Unix
- Świetne do przesyłania danych
- Integracja z przepływami
Wady
- Nie można modyfikować plików w miejscu
- Wymaga ręcznego zarządzania kopiami zapasowymi
- Mniej wygodne do operacji partii
Rozwiązanie 4: Użycie awk
Alternatywa dla złożonego przetwarzania tekstu:
awk '{sub(/\r$/,"")}1' input.txt > output.txt
# Albo bardziej jawnie:
awk 'BEGIN{RS="\r\n"} {print}' input.txt > output.txt
Tabela porównania
| Narzędzie | W miejscu | Partia | Kopie zapasowe | Szybkość | Dostępność |
|---|---|---|---|---|---|
| dos2unix | ✓ | ✓ | ✓ | Szybki | Wymaga instalacji |
| sed | ✓ | ✓ | ✓ | Średni | Wbudowane |
| tr | ✗ | ✗ | ✗ | Szybki | Wbudowane |
| awk | ✗ | ✗ | ✗ | Średni | Wbudowane |
Strategie zapobiegania
Zapobieganie końcówkom wierszy z Windowsa jest bardziej wydajne niż wielokrotne konwertowanie plików.
Konfiguracja Git
Skonfiguruj Git, aby automatycznie normalizować końcówki wierszy w różnych platformach.
Opcja 1: Poziom repozytorium (.gitattributes)
Utwórz .gitattributes w katalogu głównym repozytorium:
# Automatyczne wykrywanie plików tekstowych i normalizacja do LF
* text=auto
# Jawne deklaracje plików tekstowych
*.md text
*.txt text
*.sh text eol=lf
*.py text eol=lf
*.go text eol=lf
*.js text eol=lf
*.json text eol=lf
# Pliki binarne
*.jpg binary
*.png binary
*.pdf binary
To zapewnia spójne końcówki wierszy niezależnie od platformy i zapobiega zbędnej konwersji.
Opcja 2: Globalna konfiguracja użytkownika
Skonfiguruj zachowanie Gita dla wszystkich repozytoriów:
# Linux/macOS: Konwertuj CRLF na LF przy commitowaniu, zostaw LF bez zmian
git config --global core.autocrlf input
# Windows: Konwertuj LF na CRLF przy checkout, CRLF na LF przy commitowaniu
git config --global core.autocrlf true
# Wyłącz automatyczną konwersję (polegaj tylko na .gitattributes)
git config --global core.autocrlf false
Zalecana konfiguracja
- Programiści Linux/macOS:
core.autocrlf input - Programiści Windows:
core.autocrlf true - Wszystkie projekty: Użyj
.gitattributesdla jawnej kontroli
Normalizacja istniejącego repozytorium
Jeśli repozytorium już zawiera mieszane końcówki wierszy:
# Usuń wszystkie pliki z Git index
git rm --cached -r .
# Przywróć pliki z normalizowanymi końcówkami wierszy
git reset --hard
# Zatwierdź znormalizowane pliki
git add .
git commit -m "Znormalizuj końcówki wierszy"
Konfiguracja edytora
Skonfiguruj edytory, aby domyślnie używać końcówek wierszy Unix.
Visual Studio Code (settings.json)
{
"files.eol": "\n",
"files.encoding": "utf8",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true
}
Ustawienie dla konkretnego języka, jeśli potrzebne:
{
"[markdown]": {
"files.eol": "\n"
}
}
Vim/Neovim (.vimrc)
set fileformat=unix
set fileformats=unix,dos
Emacs (.emacs lub init.el)
(setq-default buffer-file-coding-system 'utf-8-unix)
Sublime Text (Preferences.sublime-settings)
{
"default_line_ending": "unix"
}
Edytory JetBrains (Ustawienia → Edytor → Style kodu)
- Separator wiersza: Unix i macOS (\n)
EditorConfig
Utwórz .editorconfig w katalogu głównym projektu dla kompatybilności między edytorami:
root = true
[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{sh,bash}]
end_of_line = lf
[*.bat]
end_of_line = crlf
Większość nowoczesnych edytorów automatycznie szanuje ustawienia EditorConfig, zapewniając spójność wśród członków zespołu korzystających z różnych edytorów.
Automatyzacja i skryptowanie
Integruj sprawdzanie końcówek wierszy w przepływach pracy rozwijania, aby wczesnie wykrywać problemy.
Pre-commit Git Hook
Utwórz .git/hooks/pre-commit:
#!/bin/bash
# Sprawdzenie plików z końcówkami CRLF
FILES=$(git diff --cached --name-only --diff-filter=ACM)
CRLF_FILES=""
for FILE in $FILES; do
if file "$FILE" | grep -q "CRLF"; then
CRLF_FILES="$CRLF_FILES\n $FILE"
fi
done
if [ -n "$CRLF_FILES" ]; then
echo "Błąd: Poniższe pliki mają końcówki wierszy z Windowsa (CRLF):"
echo -e "$CRLF_FILES"
echo ""
echo "Konwertuj je za pomocą: dos2unix <filename>"
echo "Lub skonfiguruj edytor, aby domyślnie używać końcówek wierszy Unix (LF)"
exit 1
fi
exit 0
Ustaw jako wykonywalny:
chmod +x .git/hooks/pre-commit
Sprawdzenie w Continuous Integration
Dodaj do potoku CI (przykład GitHub Actions):
name: Sprawdzenie końcówek wierszy
on: [push, pull_request]
jobs:
check-line-endings:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Sprawdzenie obecności CRLF
run: |
if git ls-files | xargs file | grep CRLF; then
echo "Błąd: Wykryto pliki z końcówkami CRLF"
exit 1
fi
Skrypt do konwersji w partii
Utwórz convert-line-endings.sh do utrzymania projektu:
#!/bin/bash
# Konwersja wszystkich plików tekstowych w projekcie do formatu Unix
set -e
EXTENSIONS=("md" "txt" "sh" "py" "go" "js" "json" "yml" "yaml" "toml")
echo "Konwersja końcówek wierszy do formatu Unix..."
for ext in "${EXTENSIONS[@]}"; do
echo "Przetwarzanie plików *.$ext..."
find . -name "*.$ext" ! -path "*/node_modules/*" ! -path "*/.git/*" \
-exec dos2unix {} \; 2>/dev/null || true
done
echo "Konwersja zakończona!"
Rozwiązywanie typowych problemów
Problem 1: Skrypt nadal zawodzi po konwersji
Symptom: Skrypt Bash konwertowany za pomocą dos2unix nadal pokazuje błędy interpretera.
Rozwiązanie: Sprawdź kodowanie i znak kolejki (BOM):
# Sprawdzenie kodowania
file -i script.sh
# Usunięcie BOM, jeśli obecny
sed -i '1s/^\xEF\xBB\xBF//' script.sh
# Sprawdzenie linii shebang
head -n 1 script.sh | od -c
Problem 2: Mieszane końcówki wierszy w jednym pliku
Symptom: Plik zawiera zarówno CRLF, jak i LF.
Rozwiązanie: Znormalizuj za pomocą trybu force dos2unix:
dos2unix -f filename.txt
Lub użyj bardziej agresywnego sed:
# Najpierw konwertuj wszystkie CR na nic, potem normalizuj
sed -i 's/\r//g' filename.txt
Problem 3: Git nadal pokazuje plik jako zmodyfikowany
Symptom: Po konwersji końcówek wierszy, Git pokazuje plik jako zmodyfikowany bez widocznych zmian.
Rozwiązanie: Odśwież indeks Git:
git add -u
git status
# Jeśli nadal pokazuje, sprawdź konfigurację Git
git config core.autocrlf
# Tymczasowo wyłącz autocrlf
git config core.autocrlf false
git add -u
Problem 4: Hugo zakończy się niepowodzeniem po konwersji
Symptom: Hugo nie potrafi przeanalizować frontmatter po konwersji końcówek wierszy.
Rozwiązanie: Sprawdź znak kolejki (BOM) i składnię frontmatter:
# Usunięcie BOM z plików markdown
find content -name "*.md" -exec sed -i '1s/^\xEF\xBB\xBF//' {} \;
# Sprawdzenie YAML frontmatter
hugo --debug
Problem 5: Brak dos2unix
Symptom: System nie ma dos2unix i nie można zainstalować pakietów.
Rozwiązanie: Użyj portowalnej funkcji shell:
dos2unix_portable() {
sed -i.bak 's/\r$//' "$1" && rm "${1}.bak"
}
dos2unix_portable filename.txt
Specjalne przypadki dla stron Hugo
Statyczne strony Hugo mają specjalne rozważania dotyczące końcówek wierszy, szczególnie w plikach zawartości i konfiguracji.
Konwersja zawartości Hugo
# Konwersja wszystkich plików markdown
find content -name "*.md" -exec dos2unix {} \;
# Konwersja plików konfiguracyjnych
dos2unix config.toml config.yaml
# Konwersja plików tłumaczeń i18n
find i18n -name "*.yaml" -exec dos2unix {} \;
# Konwersja szablonów layout
find layouts -name "*.html" -exec dos2unix {} \;
Obsługa frontmatter
YAML frontmatter jest szczególnie wrażliwy na problemy z końcówkami wierszy. Upewnij się, że jest spójny:
# Sprawdzenie plików zawierających frontmatter
for file in content/post/**/index.md; do
if head -n 1 "$file" | grep -q "^---$"; then
file "$file"
fi
done | grep CRLF
Skrypty budowania Hugo
Upewnij się, że skrypty budowania i wdrażania używają końcówek wierszy Unix:
dos2unix deploy.sh build.sh
chmod +x deploy.sh build.sh
Rozważania dotyczące wydajności
Dla dużych projektów z tysiącami plików, wydajność konwersji ma znaczenie.
Porównanie wydajności
Konwersja 1000 plików markdown:
# dos2unix: ~2 sekundy
time find . -name "*.md" -exec dos2unix {} \;
# sed: ~8 sekundy
time find . -name "*.md" -exec sed -i 's/\r$//' {} \;
# Równoległa konwersja dos2unix: ~0,5 sekundy
time find . -name "*.md" -print0 | xargs -0 -P 4 dos2unix
Przetwarzanie równoległe
Użyj GNU Parallel lub xargs do szybszej konwersji partii:
# Użycie xargs z równoległym wykonaniem
find . -name "*.md" -print0 | xargs -0 -P 8 dos2unix
# Użycie GNU Parallel
find . -name "*.md" | parallel -j 8 dos2unix {}
Najlepsze praktyki w rozwijaniu międzyplatformowym
Ustal konwencje zespołu, aby zapobiec problemom z końcówkami wierszy od samego początku.
1. Lista sprawdzania konfiguracji repozytorium
- Dodaj
.gitattributesz deklaracjami plików tekstowych - Ustaw
core.autocrlfw dokumentacji zespołu - Dodaj
.editorconfigdo repozytorium - Dodaj hooki pre-commit do walidacji
- Dodaj zasady dotyczące końcówek wierszy do README
2. Wprowadzanie nowych członków zespołu
Nowi członkowie zespołu powinni skonfigurować:
# Klonowanie repozytorium
git clone <repository>
cd <repository>
# Konfiguracja Git
git config core.autocrlf input # Linux/macOS
git config core.autocrlf true # Windows
# Sprawdzenie konfiguracji
git config --list | grep autocrlf
cat .gitattributes
3. Zasady przeglądania kodu
- Odrzucaj PR z zmianami tylko w końcówkach wierszy
- Używaj
git diff --ignore-cr-at-eoldo przeglądania - Włącz sprawdzanie końcówek wierszy w CI/CD
4. Dokumentacja
Dodaj do README projektu:
## Konwencja końcówek wierszy
W tym projekcie używane są końcówki wierszy Unix (LF) dla wszystkich plików tekstowych.
**Konfiguracja:**
- Linux/macOS: git config core.autocrlf input
- Windows: git config core.autocrlf true
**Konwersja plików:**
dos2unix filename.txt
Zobacz .gitattributes dla konfiguracji specyficznych dla plików.
Powiązane tematy Hugo i Linux
Praca z plikami tekstowymi na wielu platformach wymaga zrozumienia różnych narzędzi i przepływów pracy. Oto zasoby do głębszego zanurzenia się w tematach uzupełniających:
- Bash Cheat Sheet
- Markdown Cheat Sheet
- Jak zainstalować Ubuntu 24.04 i przydatne narzędzia
- Użycie bloków kodu Markdown
Zewnętrzne zasoby
Te autorytatywne źródła dostarczyły technicznych szczegółów i najlepszych praktyk dla tego artykułu: