Ни один инструмент не добавляет ничего. Это довольно путаница (но не твоя вина) по нескольким причинам.
Есть два общих окончания строки:
- 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
-s, обозначающих 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
позволяет сценарии, когда другой процесс находит файл неполным или с неправильными окончаниями строки около его конца.