Jak mogę programowo (tj. Nie używać vi
) konwertować nowe wiersze DOS / Windows na Unix?
dos2unix
I unix2dos
polecenia nie są dostępne w niektórych systemach. Jak mogę je emulować za pomocą poleceń takich jak sed
/ awk
/ tr
?
Jak mogę programowo (tj. Nie używać vi
) konwertować nowe wiersze DOS / Windows na Unix?
dos2unix
I unix2dos
polecenia nie są dostępne w niektórych systemach. Jak mogę je emulować za pomocą poleceń takich jak sed
/ awk
/ tr
?
Odpowiedzi:
Możesz użyć tr
do konwersji z DOS-a na Uniksa; można to jednak zrobić bezpiecznie tylko wtedy, gdy CR pojawia się w pliku tylko jako pierwszy bajt pary bajtów CRLF. Zazwyczaj tak jest. Następnie używasz:
tr -d '\015' <DOS-file >UNIX-file
Zauważ, że nazwa DOS-file
jest inna niż nazwa UNIX-file
; jeśli spróbujesz użyć tej samej nazwy dwa razy, skończysz bez danych w pliku.
Nie możesz tego zrobić na odwrót (ze standardowym „tr”).
Jeśli wiesz, jak wprowadzić znak powrotu karetki do skryptu ( control-V, control-Maby wpisać control-M), to:
sed 's/^M$//' # DOS to Unix
sed 's/$/^M/' # Unix to DOS
gdzie „^ M” jest znakiem kontrolnym M. Możesz także użyć mechanizmu bash
cytowania ANSI-C , aby określić zwrot karetki:
sed $'s/\r$//' # DOS to Unix
sed $'s/$/\r/' # Unix to DOS
Jeśli jednak będziesz musiał to robić bardzo często (mniej więcej raz, z grubsza mówiąc), rozsądniej jest zainstalować programy do konwersji (np. dos2unix
I unix2dos
, a może dtou
i utod
) i używać ich.
Jeśli chcesz przetwarzać całe katalogi i podkatalogi, możesz użyć zip
:
zip -r -ll zipfile.zip somedir/
unzip zipfile.zip
Spowoduje to utworzenie archiwum zip ze zmienionymi zakończeniami linii z CRLF na CR. unzip
następnie umieści przekonwertowane pliki z powrotem na swoim miejscu (i poprosi o plik po pliku - możesz odpowiedzieć: Tak-dla-wszystkich). Podziękowania dla @vmsnomad za zwrócenie na to uwagi.
tr -d '\015' <DOS-file >UNIX-file
where DOS-file
== UNIX-file
powoduje po prostu pusty plik. Plik wyjściowy musi niestety być innym plikiem.
sed
opcja GNU -i
(na miejscu); limitami są połączone pliki i dowiązania symboliczne. sort
Polecenie ma „zawsze” (od 1979 roku, jeśli nie wcześniej) poparła -o
opcję, która potrafi wymienić jeden z plików wejściowych. Jest to jednak częściowo spowodowane tym, że sort
musi odczytać wszystkie dane wejściowe, zanim będzie mógł zapisać dowolne dane wyjściowe. Inne programy sporadycznie obsługują zastępowanie jednego ze swoich plików wejściowych. Możesz znaleźć program ogólnego zastosowania (skrypt), aby uniknąć problemów w 'The Programming Environment UNIX' autorstwa Kernighan & Pike.
sed -i $'s/\r$//' filename
- do edycji w miejscu. Pracuję na maszynie, która nie ma dostępu do Internetu, więc problem stanowi instalacja oprogramowania.
tr -d "\r" < file
spójrz tutaj na przykłady, używając 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
Użyj sed -i
do konwersji w miejscu, np sed -i 's/..../' file
.
\r
:tr "\r" "\n" < infile > outfile
-d
jest opisywany częściej i nie pomoże w „tylko \r
” sytuacji.
\r
do \n
mapowania daje efekt podwójnych odstępów plików; każda pojedyncza linia CRLF kończąca się na DOS staje się \n\n
Unix.
Robienie tego z POSIX jest trudne:
POSIX Sed nie obsługuje \r
lub \15
. Nawet jeśli tak, opcja na miejscu -i
nie jest POSIX
POSIX awk robi wsparcie \r
i \15
, jednak -i inplace
opcja ta nie jest POSIX
d2u i dos2unix nie są narzędziami POSIX , ale ex jest
POSIX ex nie obsługuje \r
, \15
, \n
lub\12
Aby usunąć zwroty karetki:
ex -bsc '%!awk "{sub(/\r/,\"\")}1"' -cx file
Aby dodać zwrot karetki:
ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx file
tr
\r
Więc możesz również użyć printf '%s\n' '%!tr -d "\r"' x | ex file
(choć przyznane, to usunięte, \r
nawet jeśli nie bezpośrednio poprzedzające \n
). Ponadto -b
opcja ex
nie jest określona przez POSIX.
Możesz używać vima programowo z opcją -c {polecenie}:
Dos dla Uniksa:
vim file.txt -c "set ff=unix" -c ":wq"
Uniks do dos:
vim file.txt -c "set ff=dos" -c ":wq"
„set ff = unix / dos” oznacza zmianę formatu pliku (ff) pliku na format końca wiersza Unix / DOS
„: wq” oznacza zapisanie pliku na dysk i zamknięcie edytora (pozwalając na użycie polecenia w pętli)
vi
będzie wiedział, co :wq
znaczy. Dla tych, którzy nie mają 3 znaków, 1) otwórz obszar poleceń vi, 2) napisz i 3) wyjdź.
Aby przekonwertować plik na miejscu, użyj
dos2unix <filename>
Aby wyprowadzić przekonwertowany tekst na inny plik, użyj
dos2unix -n <input-file> <output-file>
Możesz zainstalować go na Ubuntu lub Debianie za pomocą
sudo apt install dos2unix
lub w systemie macOS za pomocą homebrew
brew install dos2unix
Ten problem można rozwiązać za pomocą standardowych narzędzi, ale istnieje wystarczająco wiele pułapek dla nieostrożnych, że zalecam zainstalowanie flip
polecenia, które zostało napisane ponad 20 lat temu przez autora Rahula Dhesi zoo
. Doskonale radzi sobie z konwersją formatów plików, na przykład unikając przypadkowego zniszczenia plików binarnych, co jest nieco zbyt łatwe, jeśli po prostu ścigasz się zmieniając każdy CRLF, który widzisz ...
Dotychczasowe rozwiązania dotyczą tylko części problemu, przekształcając CRLF DOS / Windows w LF Unixa; brakuje im tylko tego, że DOS używa CRLF jako separatora linii , podczas gdy Unix używa LF jako terminatora linii . Różnica polega na tym, że plik DOS (zwykle) nie będzie miał nic po ostatniej linii pliku, podczas gdy Unix będzie. Aby poprawnie wykonać konwersję, musisz dodać ten końcowy LF (chyba że plik ma zerową długość, tj. Nie ma w nim żadnych linii). Moje ulubione zaklęcie do tego (z nieco dodaną logiką do obsługi plików rozdzielonych CR w stylu Mac, a nie molestujących plików, które są już w formacie unixowym) to trochę perl:
perl -pe 'if ( s/\r\n?/\n/g ) { $f=1 }; if ( $f || ! $m ) { s/([^\n])\z/$1\n/ }; $m=1' PCfile.txt
Zauważ, że wysyła to Unixified wersję pliku na standardowe wyjście. Jeśli chcesz zastąpić plik wersją Unixified, dodaj -i
flagę perla .
Jeśli nie masz dostępu do dos2unix , ale możesz przeczytać tę stronę, możesz skopiować / wkleić dos2unix.py z tego miejsca.
#!/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))
Przeniesiony z superużytkownika .
dos2unix
konwertuje wszystkie pliki wejściowe. Twoje użycie oznacza -n
parametr. A prawdziwy dos2unix
to filtr, który odczytuje ze standardowego wejścia, zapisuje na standardowe wyjście, jeśli pliki nie są podane.
Łatwe kopiowanie z PCRE;
Jako skrypt lub zamień na $@
swoje pliki.
#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Spowoduje to zastąpienie plików na miejscu!
Zalecam robienie tego tylko z kopią zapasową (kontrola wersji lub w inny sposób)
--
. Wybrałem to rozwiązanie, ponieważ jest dla mnie łatwe do zrozumienia i dostosowania. Do Twojej dyspozycji są przełączniki: -p
załóż pętlę „while input”, -i
edytuj plik wejściowy na miejscu, -e
wykonaj następujące polecenie
Jeszcze prostsze rozwiązanie awk bez programu:
awk -v ORS='\r\n' '1' unix.txt > dos.txt
Technicznie „1” to twój program, b / c awk wymaga jednego, gdy podano opcję.
AKTUALIZACJA : Po ponownym odwiedzeniu tej strony od dłuższego czasu zdałem sobie sprawę, że nikt jeszcze nie opublikował wewnętrznego rozwiązania, więc oto jedno:
while IFS= read -r line;
do printf '%s\n' "${line%$'\r'}";
done < dos.txt > unix.txt
awk -v RS='\r\n' '1' dos.txt > unix.txt
awk
lub sed
rozwiązanie. Musisz także użyć, while IFS= read -r line
aby wiernie zachować linie wejściowe, w przeciwnym razie początkowe i końcowe białe znaki zostaną przycięte (alternatywnie, nie używaj nazwy zmiennej w read
poleceniu i pracuj z $REPLY
).
Musiałem tylko zastanowić się nad tym samym pytaniem (po stronie Windows, ale równie dobrze dotyczy Linuksa). Zaskakująco nikt nie wspomniał o bardzo zautomatyzowanym sposobie wykonywania konwersji CRLF <-> LF dla plików tekstowych przy użyciu starej dobrej zip -ll
opcji (Info-ZIP):
zip -ll textfiles-lf.zip files-with-crlf-eol.*
unzip textfiles-lf.zip
UWAGA: spowoduje to utworzenie pliku zip z zachowaniem oryginalnych nazw plików, ale konwersją zakończeń linii do LF. Następnieunzip
rozpakowałbym pliki jako skompresowane, czyli z ich oryginalnymi nazwami (ale z końcówkami LF), prosząc w ten sposób o zastąpienie lokalnych oryginalnych plików, jeśli takie istnieją.
Odpowiedni fragment z zip --help
:
zip --help
...
-l convert LF to CR LF (-ll CR LF to LF)
co ciekawe w mojej git-bash na Windowsie sed ""
zrobiłem już lewę:
$ 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
Domyślam się, że sed ignoruje je podczas odczytu linii z wejścia i zawsze zapisuje na wyjściu zakończenia linii unixowych.
W przypadku systemu Mac OSX, jeśli masz zainstalowany program Homebrew [ http://brew.sh/][1]
brew install dos2unix
for csv in *.csv; do dos2unix -c mac ${csv}; done;
Upewnij się, że wykonałeś kopie plików, ponieważ to polecenie zmodyfikuje pliki na miejscu. Opcja -c mac sprawia, że przełącznik jest zgodny z systemem osx.
-c mac
, czyli do konwertowania CR
tylko nowych linii przed systemem OS X. Chcesz używać tego trybu tylko do plików do i z Mac OS 9 lub wcześniejszych.
Możesz użyć awk. Ustaw separator rekordów ( RS
) na wyrażenie regularne, które pasuje do wszystkich możliwych znaków nowej linii lub znaków. I ustaw separator rekordów wyjściowych ( ORS
) na znak nowej linii w stylu uniksowym.
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
git diff
pokazuje ^ M, edytowany w vimie)
W Linuksie łatwo jest przekonwertować ^ M (ctrl-M) na * nix nowe linie (^ J) za pomocą sed.
Będzie to coś takiego w interfejsie CLI, tak naprawdę nastąpi przerwanie linii w tekście. Jednak \ przekazuje to ^ J do sed:
sed 's/^M/\
/g' < ffmpeg.log > new.log
Możesz to zrobić, używając ^ V (ctrl-V), ^ M (ctrl-M) i \ (ukośnik odwrotny) podczas pisania:
sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log
sed --expression='s/\r\n/\n/g'
Ponieważ w pytaniu mowa jest o sed, jest to najprostszy sposób użycia sed, aby to osiągnąć. To, co mówi to wyrażenie, zastępuje wszystkie znaki powrotu karetki i znak wiersza tylko wierszami. Właśnie tego potrzebujesz, kiedy przechodzisz z Windowsa na Unixa. Sprawdziłem, czy to działa.
Stworzyłem skrypt w oparciu o zaakceptowaną odpowiedź, więc możesz go przekonwertować bezpośrednio, bez potrzeby dodatkowego pliku na końcu, a następnie usunąć i zmienić jego nazwę.
convert-crlf-to-lf() {
file="$1"
tr -d '\015' <"$file" >"$file"2
rm -rf "$file"
mv "$file"2 "$file"
}
tylko upewnij się, że jeśli masz plik taki jak „plik1.txt”, że „plik1.txt2” jeszcze nie istnieje lub zostanie zastąpiony, używam go jako tymczasowego miejsca do przechowywania pliku.
Próbowałem sed 's / ^ M $ //' file.txt na OSX, a także kilka innych metod ( http://www.thingy-ma-jig.co.uk/blog/25-11-2010/fixing- dos-line-endings lub http://hintsforums.macworld.com/archive/index.php/t-125.html ). Żaden nie działał, plik pozostał niezmieniony (do odtworzenia ^ M potrzebny był Ctrl-v Enter). W końcu użyłem TextWrangler. Nie jest to ściśle wiersz poleceń, ale działa i nie narzeka.
dos2unix
za pomocą menedżera pakietów, to naprawdę jest znacznie prostsze i istnieje na większości platform.