Як я можу програмно (тобто не користуватися vi
) конвертувати нові рядки DOS / Windows в Unix?
Команди dos2unix
і та unix2dos
команди недоступні в певних системах. Як я можу емулювати їх з командами типу sed
/ awk
/ tr
?
Як я можу програмно (тобто не користуватися vi
) конвертувати нові рядки DOS / Windows в Unix?
Команди dos2unix
і та unix2dos
команди недоступні в певних системах. Як я можу емулювати їх з командами типу sed
/ awk
/ tr
?
Відповіді:
Ви можете використовувати tr
для перетворення з DOS в Unix; однак, ви можете це зробити безпечно, лише якщо CR відображається у вашому файлі лише як перший байт пари байтів CRLF. Зазвичай це так. Потім ви використовуєте:
tr -d '\015' <DOS-file >UNIX-file
Зауважте, що ім’я DOS-file
відрізняється від імені UNIX-file
; якщо ви спробуєте використати те саме ім’я двічі, у вас виявиться відсутність даних у файлі.
Ви не можете зробити це навпаки (зі стандартним 'tr').
Якщо ви знаєте, як ввести повернення каретки до сценарію ( control-V, control-Mщоб ввести контроль-M), тоді:
sed 's/^M$//' # DOS to Unix
sed 's/$/^M/' # Unix to DOS
де '^ M' - символ керування-M. Ви також можете використовувати механізм bash
цитування ANSI-C для визначення повернення перевезення:
sed $'s/\r$//' # DOS to Unix
sed $'s/$/\r/' # Unix to DOS
Однак якщо вам доведеться це робити дуже часто (не раз, грубо кажучи), набагато розумніше встановити програми перетворення (наприклад, dos2unix
і unix2dos
, можливо, dtou
і utod
) та використовувати їх.
Якщо вам потрібно обробити цілі каталоги та підкаталоги, ви можете використовувати zip
:
zip -r -ll zipfile.zip somedir/
unzip zipfile.zip
Це створить zip-архів із закінченнями рядків, зміненими з CRLF на CR. unzip
потім поверне перетворені файли на місце (і попросить вас файл по файлу - ви можете відповісти: Так, всім). Подяка @vmsnomad за вказівку на це.
tr -d '\015' <DOS-file >UNIX-file
де DOS-file
== UNIX-file
просто призводить до порожнього файлу. На жаль, у вихідному файлі має бути інший файл, на жаль.
sed
варіант -i
(для на місці) роботи; межі - це пов'язані файли та посилання. sort
Команда має «завжди» (з 1979 року, якщо не раніше) підтримує -o
варіант , який може перерахувати один з вхідних файлів. Однак це частково тому, що він sort
повинен прочитати весь його вклад, перш ніж він зможе написати будь-який із своїх результатів. Інші програми спорадично підтримують перезапис одного з вхідних файлів. Ви можете знайти програму (сценарій) загального призначення, щоб уникнути проблем у "Програмі UNIX програмування" від Kernighan & Pike.
sed -i $'s/\r$//' filename
- для редагування на місці. Я працюю на машині, яка не має доступу до Інтернету, тому встановлення програмного забезпечення є проблемою.
tr -d "\r" < file
подивіться тут приклади, використовуючи 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
Використовуйте sed -i
для перетворення на місці, наприклад sed -i 's/..../' file
.
\r
:tr "\r" "\n" < infile > outfile
-d
характеризується більш часто і не допоможе в «тільки \r
» ситуації.
\r
для \n
відображення має ефект подвійного інтервалу між файлами; кожен рядок CRLF, що закінчується в DOS, стає \n\n
Unix.
Робити це за допомогою POSIX складно:
POSIX Sed не підтримує \r
або \15
. Навіть якщо це було, варіант на місці -i
- це не POSIX
POSIX Awk робить підтримку \r
і \15
, проте -i inplace
варіант не POSIX
d2u і dos2unix НЕ POSIX утиліт , але колишній є
POSIX колишній не підтримує \r
, \15
, \n
або\12
Щоб видалити повернення вагона:
ex -bsc '%!awk "{sub(/\r/,\"\")}1"' -cx file
Щоб додати декларації про перевезення:
ex -bsc '%!awk "{sub(/$/,\"\r\")}1"' -cx file
tr
\r
Таким чином, ви також можете використовувати printf '%s\n' '%!tr -d "\r"' x | ex file
(хоча це надано, це видалено, \r
навіть якщо це не було раніше \n
). Крім того , -b
варіант ex
не визначений POSIX.
Ви можете використовувати vim програмно за допомогою параметра -c {command}:
Dos для Unix:
vim file.txt -c "set ff=unix" -c ":wq"
Unix для дос:
vim file.txt -c "set ff=dos" -c ":wq"
"встановити ff = unix / dos" означає змінити формат файлу (ff) файлу на формат Unix / DOS в кінці рядка
": wq" означає записати файл на диск і вийти з редактора (що дозволяє використовувати команду в циклі)
vi
буде знати, що :wq
означає. Для тих, хто не має 3 символів, означає 1) відкрити командну область vi, 2) написати та 3) вийти.
За допомогою AWK ви можете:
awk '{ sub("\r$", ""); print }' dos.txt > unix.txt
За допомогою Perl ви можете:
perl -pe 's/\r$//' < dos.txt > unix.txt
awk
рішення.
Для перетворення файлу на місці використання
dos2unix <filename>
Для виведення конвертованого тексту в інше використання файлу
dos2unix -n <input-file> <output-file>
Ви можете встановити його на Ubuntu або Debian з
sudo apt install dos2unix
або на macOS, використовуючи домашню мову
brew install dos2unix
Цю проблему можна вирішити за допомогою стандартних інструментів, але є достатньо багато пасток для необережного, що я рекомендую вам встановити flip
команду, написану понад 20 років тому Рахулом Десі, автором zoo
. Це прекрасна робота по перетворенню форматів файлів, уникаючи, наприклад, уникнення випадкового знищення бінарних файлів, що занадто просто, якщо ви просто змагаєтесь навколо зміни кожного CRLF, який ви бачите ...
Наразі розміщені рішення стосуються лише частини проблеми, перетворюючи CRLF DOS / Windows у LF Unix; частина, якої вони відсутні, полягає в тому, що DOS використовує CRLF як роздільник рядків , а Unix використовує LF як термінатор лінії . Різниця полягає в тому, що файл DOS (як правило) після останнього рядка у файлі нічого не матиме, тоді як Unix буде. Щоб виконати перетворення належним чином, вам потрібно додати цей остаточний LF (якщо файл не має нульової довжини, тобто у ньому взагалі немає рядків). Моя улюблена заклик до цього (з трохи доданої логіки для обробки файлів, розділених CR-стилем Mac, а не молетування файлів, які вже є у форматі Unix) - це трохи перл:
perl -pe 'if ( s/\r\n?/\n/g ) { $f=1 }; if ( $f || ! $m ) { s/([^\n])\z/$1\n/ }; $m=1' PCfile.txt
Зауважте, що це надсилає Уніфіковану версію файлу до stdout. Якщо ви хочете замінити файл на Уніфіковану версію, додайте -i
прапор Perl .
Якщо у вас немає доступу до dos2unix , але ви можете прочитати цю сторінку, ви можете скопіювати / вставити dos2unix.py звідси.
#!/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))
Перехресне повідомлення від суперрусера .
dos2unix
перетворює всі вхідні файли за замовчуванням. Ваше використання має на увазі -n
параметр. І справжній dos2unix
- це фільтр, який читає з stdin, пише в stdout, якщо файли не задані.
Супер пупер легко з PCRE;
Як сценарій, або замініть $@
файли.
#!/usr/bin/env bash
perl -pi -e 's/\r\n/\n/g' -- $@
Це замінить ваші файли на місці!
Я рекомендую робити це лише за допомогою резервної копії (керування версіями чи іншим способом)
--
. Я вибрав це рішення, тому що це легко зрозуміти і адаптувати для мене. FYI, це те, що роблять перемикачі: -p
припустимо цикл "while input", -i
відредагуйте вхідний файл на місці, -e
виконайте наступну команду
Ще більш просте рішення для програми:
awk -v ORS='\r\n' '1' unix.txt > dos.txt
Технічно "1" - це ваша програма, але для отримання додаткової опції потрібна програма "b".
ОНОВЛЕННЯ : Після перегляду цієї сторінки вперше за довгий час я зрозумів, що ще ніхто не опублікував внутрішнє рішення, ось ось одне:
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
або sed
рішення. Крім того, ви повинні використовувати while IFS= read -r line
для достовірного збереження вхідних рядків, інакше пробіл проміжних та кінцевих пробілів обрізаний (як альтернатива, не використовуйте в read
команді імені змінної та не працюйте з нею $REPLY
).
Доводилося просто замислюватися над тим самим питанням (на стороні Windows, але однаково застосовно до Linux.) На жаль, ніхто не згадав про дуже автоматизований спосіб здійснення перетворення CRLF <-> LF для текстових файлів, використовуючи старий добрий zip -ll
варіант (Info-ZIP):
zip -ll textfiles-lf.zip files-with-crlf-eol.*
unzip textfiles-lf.zip
ПРИМІТКА: це створило б zip-файл, зберігаючи оригінальні імена файлів, але перетворюючи закінчення рядків у LF. Потім unzip
буде вилучено файли як zip'ed, тобто з їх оригінальними іменами (але з LF-закінченнями), тим самим запропонувавши перезаписати локальні оригінальні файли, якщо такі є.
Відповідний уривок із zip --help
:
zip --help
...
-l convert LF to CR LF (-ll CR LF to LF)
Цікаво, що в моєму git-bash на Windows вже sed ""
зроблено трюк:
$ 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
Я здогадуюсь, що sed ігнорує їх, читаючи рядки з вхідних даних і завжди записує закінчення рядків Unix на виході.
Для ОС Mac OSX, якщо у вас встановлено домашню програму [ http://brew.sh/ freedict1]
brew install dos2unix
for csv in *.csv; do dos2unix -c mac ${csv}; done;
Переконайтеся, що ви зробили копії файлів, оскільки ця команда змінить файли на місці. Опція -c mac робить перемикач сумісним з osx.
-c mac
, що призначено для перетворення попередньо OS X-тільки нових CR
рядків. Ви хочете використовувати цей режим лише для файлів до та з Mac OS 9 або раніше.
Ви можете використовувати awk. Встановіть роздільник записів ( RS
) на регулярне вираження, яке відповідає всім можливим символам або новим рядкам. І встановіть роздільник записів виводу ( ORS
) на символ нового рядка в стилі Unix.
awk 'BEGIN{RS="\r|\n|\r\n|\n\r";ORS="\n"}{print}' windows_or_macos.txt > unix.txt
git diff
шоу ^ M, редагується vim)
У Linux легко перетворити ^ M (ctrl-M) в * nix newlines (^ J) за допомогою sed.
Це буде щось подібне на CLI, насправді в тексті буде розрив рядка. Однак \ передає ^ J разом із sed:
sed 's/^M/\
/g' < ffmpeg.log > new.log
Ви отримуєте це, використовуючи ^ V (ctrl-V), ^ M (ctrl-M) та \ (зворотний косий рядок) під час введення:
sed 's/^V^M/\^V^J/g' < ffmpeg.log > new.log
sed --expression='s/\r\n/\n/g'
Оскільки в питанні йдеться про sed, це найбільш прямий спосіб використання sed для досягнення цього. Що говорить вираз, замініть всі перевезення та повернення рядків лише на подачу рядків. Це те, що вам потрібно, коли ви переходите з Windows в Unix. Я перевірив, що це працює.
Я створив скрипт на основі прийнятої відповіді, щоб ви могли його перетворити безпосередньо, не потребуючи додаткового файлу в кінцевому підсумку, а потім видаляти та перейменувати.
convert-crlf-to-lf() {
file="$1"
tr -d '\015' <"$file" >"$file"2
rm -rf "$file"
mv "$file"2 "$file"
}
просто переконайтесь, що у вас є такий файл, як "file1.txt", що "file1.txt2" вже не існує, або він буде перезаписаний, я використовую це як тимчасове місце для зберігання файлу.
Я спробував sed 's / ^ M $ //' file.txt на OSX, а також кілька інших методів ( http://www.thingy-ma-jig.co.uk/blog/25-11-2010/fixing- dos-line-endings або http://hintsforums.macworld.com/archive/index.php/t-125.html ). Жоден не працював, файл залишався незмінним (для відтворення ^ M) потрібен btw Ctrl-v Enter. Врешті-решт я використав TextWrangler. Це не строго командний рядок, але він працює, і він не скаржиться.
dos2unix
за допомогою менеджера пакунків, це дійсно набагато простіше і існує на більшості платформ.