Como faço para impedir que o sed adicione caracteres extras de nova linha

17

Estou executando os 2 sedcomandos a seguir . O primeiro adiciona caracteres de nova linha onde eu os quero, o segundo também adiciona caracteres de nova linha onde eu os quero, MAS também adiciona um adicional no final do arquivo onde não havia um antes.

sed -e 's|\<LIST_G_STATEMENT>|&\
|g' ${XMLDIR}/statement_tmp_1.xml > ${XMLDIR}/statement_tmp_2.xml

sed -e 's|\</LIST_G_STATEMENT>|&\
|g' ${XMLDIR}/statement_tmp_2.xml > ${XMLDIR}/statement_tmp_3.xml

O uso od -cem todos os três arquivos fornece a seguinte saída.

statement_tmp_1.xml (não \nno final do arquivo)

1314700    T   A   T   E   M   E   N   T   >   <   /   L   I   S   T   _
1314720    G   _   S   T   A   T   E   M   E   N   T   >   <   /   G   _
1314740    S   E   T   U   P   >   <   /   L   I   S   T   _   G   _   S
1314760    E   T   U   P   >   <   /   A   R   X   S   G   P   O   >
1314777

statement_tmp_2.xml (não \nno final do arquivo)

1314700    S   T   A   T   E   M   E   N   T   >   <   /   L   I   S   T
1314720    _   G   _   S   T   A   T   E   M   E   N   T   >   <   /   G
1314740    _   S   E   T   U   P   >   <   /   L   I   S   T   _   G   _
1314760    S   E   T   U   P   >   <   /   A   R   X   S   G   P   O   >
1315000

statement_tmp_3.xml ( \nno final do arquivo - de onde veio?)

1314700    S   T   A   T   E   M   E   N   T   >   <   /   L   I   S   T
1314720    _   G   _   S   T   A   T   E   M   E   N   T   >  \n   <   /
1314740    G   _   S   E   T   U   P   >   <   /   L   I   S   T   _   G
1314760    _   S   E   T   U   P   >   <   /   A   R   X   S   G   P   O
1315000    >  \n
1315002

Estou executando o AIX 5.3

Basicamente, eu quero que ele pare de adicionar o extra \nou encontre uma maneira de removê-lo.

jonnohudski
fonte
Apenas uma pergunta: por que você está usando uma nova linha literal no seu padrão de substituição quando poderia ter usado s|...|&\n|também?
Joseph R.
11
@JosephR. \nno lado direito não é portátil.
Stéphane Chazelas
@StephaneChazelas Isso é estranho. É uma coisa CR vs CRLF?
Joseph R.
2
Um arquivo que não termina em um caractere de nova linha não é um arquivo de texto; portanto, o comportamento dos utilitários de texto não é especificado . Use perlou outra ferramenta que possa lidar com dados binários.
Stéphane Chazelas
4
@JosephR. Não, \<LF>é a maneira tradicional e POSIX de adicionar um caractere LF. \nnormalmente substituiria um npersonagem em qualquer coisa, exceto GNU sed.
Stéphane Chazelas

Respostas:

10

Você deve considerar-se com sorte porque o AIX sedadicionou esses caracteres de nova linha ausentes.

Um arquivo não vazio que não termine com um caractere de nova linha não é um arquivo de texto (pelo menos conforme a definição POSIX de um arquivo de texto), pois um arquivo de texto deve conter linhas e as linhas são (não muito longa) sequência de caracteres terminados por um caractere de nova linha; portanto, o comportamento dos utilitários de texto como sedele não é especificado e, na prática, varia de implementação para implementação.

Alguma sedimplementação teria descartado esses caracteres espúrios após a última linha.

AFAIK, os xmlarquivos devem ser arquivos de texto, o que significa que sedapenas foi corrigido.

Se você precisar que esse arquivo não termine com um caractere de nova linha, poderá usar perlou outras ferramentas que possam lidar com dados que não são de texto.

perl -pe 's|<LIST_G_STATEMENT>|$&\n|g'
Stéphane Chazelas
fonte
11
A nova linha final é útil, se você espera canalizar sua sedsaída para qualquer outro utilitário Unix padrão. Honestamente, eu não percebi sedisso há anos , já que as substituições de comandos do Bourne shell $(sed 's/bas/replac/' <<<'basement')cortam furtivamente a nova linha final, se houver uma. Mas não são momentos em que você definitivamente não quer; por exemplo , manipular o texto da área de transferência do X com sed. FYI, GNU sed, se disponível, não adiciona uma nova linha final se você a usar pcom a -nopção, conforme descrito nesta resposta SE .
TheDudeAbides
0

Aqui está uma maneira de remover a nova linha final de um arquivo usando dd:

printf "" | dd  of='/path/to/file' seek=<filesize_in_bytes - 1> bs=1 count=1

Para testar se um arquivo termina com uma nova linha, você pode usar:

tail -c 1 /path/to/file | tr -dc '\n' | wc -c

E para obter o tamanho do arquivo em bytes, use:

wc -c < /path/to/file
chan
fonte
0

De acordo com esta AIX manual do IBM tailfaz -reverse - que parece muito legal. Desde que seu arquivo tenha menos de 20 KB, o seguinte deve funcionar:

tail -r <file | dd bs=1 skip=1 | tail -r >file.new
mikeserv
fonte