Konwertowanie tekstu z Windows na format Linux

Zarządzanie konwersjami końcówek linii między platformami

Page content

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.

konwersja dokumentu windows-to-unix 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\n lub CRLF, heks 0D 0A)
  • Linux/Unix: Tylko znak nowego wiersza (\n lub LF, heks 0A)
  • Klasyczny system Mac OS: Tylko znak powrotu karetki (\r lub CR, heks 0D)

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 -i modyfikuje 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 .gitattributes dla 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 .gitattributes z deklaracjami plików tekstowych
  • Ustaw core.autocrlf w dokumentacji zespołu
  • Dodaj .editorconfig do 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-eol do 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:

Zewnętrzne zasoby

Te autorytatywne źródła dostarczyły technicznych szczegółów i najlepszych praktyk dla tego artykułu: