Esta questão está intimamente relacionada a: Como inserir texto antes da primeira linha de um arquivo? . Eu deliberadamente fiz o título parecido com o daquela questão para destacar isso.
Exceto que o arquivo de destino é UTF-8 com BOM.
Então, eu quero adicionar uma primeira linha a um arquivo que tem bytes UTF-8 BOM em seu cabeçalho ( 0xef 0xbb 0xbf
caracteres). Pelo menos os arquivos UTF-8 com BOM que eu tenho aqui começam com isso.
Se eu simplesmente seguir em frente e seguir as soluções na questão relacionada,
sed "1i My First line is now this." file.txt
Eu obterei (no VSCode no meu caso) algo como
My First line is now this.
?The first line was this one
Second line and so on
Estando ?
na segunda linha o caractere UTF-8 para expressar algo não imprimível.
Outra consequência, como seria de se esperar, é que o arquivo não abre mais como UTF-8 com BOM e agora dependemos dos recursos do editor de texto para "adivinhar" sua codificação. Determinamos um padrão em nosso projeto para ter arquivos com BOM para garantir que tudo esteja na mesma codificação.
Como preservo o cabeçalho da lista de materiais no arquivo ao adicionar o texto?
Da mesma pergunta relacionada, uma resposta abre a porta para a solução aqui: https://unix.stackexchange.com/a/455250/413756
Então, com um pouco de ajustes em regex select-groups, cheguei a esta expressão:
E obtive o resultado desejado, preservando o cabeçalho UTF-8 BOM no arquivo e até mesmo fazendo a substituição em arquivos que eventualmente não corresponderão ao cabeçalho.
Se você tiver certeza de que todos os arquivos são BOM, isso deve ser suficiente:
Observe que isso captura especificamente arquivos BOM UTF-8 com o mesmo cabeçalho exato que tenho aqui. Acredito que sequências de bytes diferentes podem acontecer em formatos diferentes, o que depende de cada caso -- e provavelmente é possível com o regex acima (basta adicionar/substituir
|\xXX\xYY\xZZ
ou corresponder ao grupo selecionado).Observe também que em ambas as substituições estou assumindo que o final de linha dos arquivos é apenas
\n
(unix LF), não\r\n
(windows CRLF).A sintaxe acima funcionou no GNU Sed (Cygwin e provavelmente na maioria das distribuições Linux).
UTF-8 BOM é muito não-Unix, provavelmente vem do mundo Microsoft. Então o fim de linha provavelmente também será CRLF em vez de LF e pode até haver mais idiossincrasias da Microsoft para lidar. Se você quiser processá-las com ferramentas Unix/GNU, provavelmente é melhor fazer:
Para edição no local (aqui usando
-i
edição n-place no estilo GNU) ou:Para processar em tempo real (aqui sem a necessidade de
sed
) e ter o resultado armazenado (de volta no formato Microsoft com BOM) no novo arquivo.Outra abordagem é usar
perl
(de onde algumassed
implementações copiaram sua-i
opção) e usar oFile::BOM
módulo como uma camada de E/S, além da:crlf
camada de E/S para lidar com terminações de linha da Microsoft:Exemplo:
Veja a BOM movida para o início da nova linha e a primeira linha também delimitada com CRLF.
Uma abordagem para lidar com arquivos que podem ter terminações de linha Microsoft ou Unix e um BOM UTF-8 ou não, você pode fazer algo como:
Onde, na primeira linha (
$. == 1
),K
mantemos o BOM, se houver, e então inserimos a nova linha seguida por um\r
se ele foi encontrado no final da primeira linha, então\n
, então a primeira linha original.Isso não insere a nova linha se o arquivo estava inicialmente vazio (sem BOM), mas depois não saberia se deveria adicionar a nova linha com uma terminação de linha Microsoft ou Unix.