Nenhuma ferramenta está adicionando nada. É uma grande confusão (mas não é sua culpa) por causa de algumas razões.
Existem dois finais de linha comuns:
- Estilo Unix, um caractere denotado
LF
(ou\n
ou0x0a
), - estilo Windows, dois caracteres,
CRLF
(ou\r\n
ou0x0d 0x0a
).
Você faz o download de dois URLs diferentes. Parece que o servidor afirma que cada arquivo é text/plain
, então eles devem usar CRLF
. A segunda (a que você usa curl
) usa CRLF
, mas a primeira (a que você usa wget
) usa ilegalmente a LF
.
Se você fizer o download apenas do primeiro URL (não importa se com wget
ou curl
) e armazenar o resultado em um arquivo hosts1
, file hosts1
produzirá:
hosts1: UTF-8 Unicode text
(Isso significa que os finais de linha são LF
, caso contrário, seria UTF-8 Unicode text, with CRLF line terminators
).
Se você fizer o download apenas do segundo URL e armazenar o resultado em um arquivo hosts2
, file hosts2
produzirá:
hosts2: ASCII text, with CRLF line terminators
Se você fizer o download de ambos para o mesmo arquivo (digamos hosts12
), obterá LF
como terminações de linha para linhas que vieram do primeiro URL e CRLF
como finais de linha para linhas que veio da segunda URL.
Na prática, qualquer ferramenta que tente dizer se um arquivo usa LF
ou CRLF
examina no máximo algumas linhas iniciais, nem todas elas. Experimente file hosts12
e você terá:
hosts12: UTF-8 Unicode text
exatamente como era para hosts1
. O mesmo acontece quando você vim hosts12
: o editor detecta finais de linha como LF
com base no início do arquivo. Então você pula para o final e vê muitos ^M
-s que denotam CR
caracteres. vim
imprime porque não considera CR
como parte da linha correta que termina neste caso.
No entanto, quando você vim hosts2
, o editor detecta corretamente os finais de linha como CRLF
. Os mesmos caracteres CR
que foram impressos como ^M
anterior, agora estão ocultos de você porque vim
os considera partes de finais de linha adequados. Se você adicionasse uma nova linha manualmente, vim
usaria a linha no estilo Windows terminando mesmo se você estivesse no Unix. Você pode achar que o arquivo é "perfeitamente normal", mas não é um arquivo de texto normal do Unix.
A confusão é porque os dois arquivos no servidor usam diferentes terminações de linha; então vim
tenta ser inteligente.
No Linux (Unix em geral), você deseja que seu /etc/hosts
use LF
como terminações de linha. Veja as definições POSIX da linha e caractere de nova linha . É explicitamente declarado que o caractere é \n
:
3.243 Newline Character (
<newline>
)
A character that in the output stream indicates that printing should start at the beginning of the next line. It is the character designated by'\n'
in the C language.
Eu não acho que as ferramentas são obrigadas a suportar \r\n
. A solução simples é executar wget … && curl … >> …
exatamente como você fez e invocar dos2unix /etc/hosts
.
Se eu fosse você, trabalharia com outro arquivo, digamos /etc/hosts.tmp
. Eu usaria wget
, curl
, dos2unix
, chmod --reference=/etc/hosts
, chown --reference=/etc/hosts
. Somente quando o arquivo estiver completo, eu usaria mv
para substituir /etc/hosts
. Esta funcionalidade de rename(2)
é relevante:
If
newpath
already exists, it will be atomically replaced, so that there is no point at which another process attempting to accessnewpath
will find it missing.
Assim, qualquer processo encontraria o antigo /etc/hosts
(antes de mv
) ou o novo (após mv
). Sua abordagem atual, trabalhando diretamente com /etc/hosts
, permite cenários em que outro processo encontra o arquivo incompleto ou com finais de linha errados próximos do fim.