Ни один инструмент не добавляет ничего. Это довольно путаница (но не твоя вина) по нескольким причинам.
Есть два общих окончания строки:
- Unix-стиль, один символ обозначается
LF
(или \n
или 0x0a
),
- Стиль Windows, два символа,
CRLF
(или \r\n
или 0x0d 0x0a
).
Вы скачиваете с двух разных URL. Кажется, сервер утверждает, что каждый файл является text/plain
, поэтому они должны использовать CRLF
. Второй (тот, который вы curl
) действительно использует CRLF
, но первый (тот, который вы wget
) незаконно использует вместо одного LF
.
Если вы загрузите только с первого URL (независимо от того, используете ли вы wget
или curl
) и сохраните результат в файле hosts1
, то file hosts1
выдаст:
hosts1: UTF-8 Unicode text
(Это означает, что окончания строки LF
, в противном случае это будет UTF-8 Unicode text, with CRLF line terminators
).
Если вы загружаете только со второго URL и сохраняете результат в файле hosts2
, то file hosts2
выдаст:
hosts2: ASCII text, with CRLF line terminators
Если вы загрузите оба файла в один и тот же файл (скажем, hosts12
) таким же образом, вы получите LF
качестве окончаний строк для строк, которые пришли из первого URL, и CRLF
качестве окончаний строк для строк, которые пришли из второго URL.
На практике любой инструмент, который пытается определить, использует ли файл LF
или CRLF
проверяет не более нескольких начальных строк, но не все из них. Попробуйте file hosts12
и вы получите:
hosts12: UTF-8 Unicode text
Точно так же, как это было для hosts1
. То же самое происходит, когда вы используете vim hosts12
: редактор определяет окончания строки как LF
на основе начала файла. Затем вы переходите к концу и видите много ^M
символов, которые обозначают символы CR
. vim
печатает их, потому что не считает CR
частью правильной строки, заканчивающейся в этом случае.
Однако, когда вы используете vim hosts2
, редактор правильно определяет окончания строк как CRLF
. Те же символы CR
которые были напечатаны как ^M
ранее, теперь скрыты от вас, потому что vim
считает их частью правильных окончаний строк. Если вы добавите новую строку вручную, vim
будет использовать конец строки в стиле Windows, даже если вы работаете в Unix. Вы можете подумать, что файл "совершенно нормальный", но это не обычный текстовый файл Unix.
Путаница заключается в том, что два файла на сервере используют разные окончания строк; тогда vim
пытается быть умным
В Linux (Unix в целом) вы хотите, чтобы ваши /etc/hosts
использовали LF
качестве окончания строки. См. Определения строки и символа новой строки в POSIX. Явно указано, что символ \n
:
3.243 Символ новой строки (<newline>
новая строка > )
Символ, который в выходном потоке указывает, что печать должна начинаться в начале следующей строки. Это символ, обозначенный '\n'
на языке Си.
Я не думаю, что инструменты обязаны поддерживать \r\n
тогда. Простое решение - запустить wget … && curl … >> …
точно так же, как вы это сделали, затем вызвать dos2unix /etc/hosts
.
На вашем месте я бы работал с другим файлом, скажем /etc/hosts.tmp
. Я бы использовал wget
, curl
, dos2unix
, chmod --reference=/etc/hosts
, chown --reference=/etc/hosts
. Только когда файл будет mv
, я бы заменил его на /etc/hosts
. Эта функция rename(2)
имеет отношение:
Если newpath
уже существует, он будет атомарно заменен, так что не будет точки, в которой другой процесс, пытающийся получить доступ к newpath
, обнаружит, что он отсутствует.
Таким образом, любой процесс найдет либо старый /etc/hosts
(до mv
), либо новый (после mv
). Ваш текущий подход, напрямую работающий с /etc/hosts
допускает сценарии, когда другой процесс находит файл неполным или с неправильным окончанием строки рядом с его концом.