faz a entrada de saída copiar todos os caracteres invisíveis para o novo arquivo?

3

Eu preciso pegar as primeiras linhas de um arquivo de texto longo para algumas correções de bugs em um arquivo menor (um script Python não digere o arquivo de texto grande como pretendido). No entanto, para que a correção de erros faça algum sentido, eu realmente preciso que as linhas sejam cópias perfeitas, basicamente byte por byte, e capte qualquer problema em potencial com codificação de caracteres, caracteres de fim-de-linha, caracteres invisíveis ou o que não estiver o original txt. Será que a seguinte solução simples conseguirá isso ou perderia algo usando a saída de head ?

head infile.txt > output.txt

Uma pergunta mais geral sobre a cópia binária com head , dd , ou então está publicada aqui .

    
por László 03.03.2016 / 11:07

3 respostas

10

POSIX diz que a entrada para head é um arquivo de texto e define um arquivo de texto:

3.397 Text File

A file that contains characters organized into zero or more lines. The lines do not contain NUL characters and none can exceed {LINE_MAX} bytes in length, including the <newline> character. Although POSIX.1-2008 does not distinguish between text files and binary files (see the ISO C standard), many utilities only produce predictable or meaningful output when operating on text files. The standard utilities that have such restrictions always specify "text files" in their STDIN or INPUT FILES sections.

Portanto, existe a possibilidade de perder informações.

    
por 03.03.2016 / 11:16
5

Aparentemente, head de fato distorce sua entrada quando não é um arquivo de texto:

$ wc /bin/ls
   431   3454 126496 /bin/ls
$ head -n 431 /bin/ls > a
 wc a
   431   3447 125378 a
$ diff a /bin/ls
Binary files a and /bin/ls differ
$ md5sum /bin/ls a
42846aa64774a99f0f1feba36ec2e099  /bin/ls
de032f5aa5ef356fb7d5ab4dc622df2e  a
$ wc -c /bin/ls a
126496 /bin/ls
125378 a

Stéphane Chazelas faz um bom ponto nos comentários:

wc -l reports the number of newlines. /bin/ls likely has more bytes after the last occurrence of 0xa, which head -n 431 won't output. GNU tools (which you seem to be using) generally can deal with binary data (NUL bytes and arbitrarily long lines).

Portanto, o motivo pelo qual a saída está errada ao usar head -n é que há dados extras após o último caractere \n . Olhando para o código-fonte para o GNU head , posso confirmar que tanto a função que lê por linhas quanto a que lê por bytes, usa a mesma chamada safe_open() , então não deveria haver nenhuma diferença entre o que eles são capazes de retornar. Isso sugeriria que usar a implementação GNU de head (como normalmente é encontrado na maioria dos sistemas operacionais não-embarcados usando Linux) é bastante seguro.

No entanto, parece que funciona corretamente se você disser para trabalhar em bytes em vez de linhas (de man head ):

  -c, --bytes=[-]NUM
          print  the  first  NUM bytes of each file; with the leading '-',
          print all but the last NUM bytes of each file

Com a opção -c , parece criar arquivos idênticos:

$ wc -c /bin/ls
126496 /bin/ls
$ head -c 126496 /bin/ls > a
$
$ md5sum /bin/ls a
42846aa64774a99f0f1feba36ec2e099  /bin/ls
42846aa64774a99f0f1feba36ec2e099  a

Este também é o mesmo resultado obtido por dd :

$ dd if=/bin/ls of=a bs=126496 count=1
1+0 records in
1+0 records out
126496 bytes (126 kB, 124 KiB) copied, 0.000469919 s, 269 MB/s
$ diff a /bin/ls
$

Não consigo apontar para nenhuma documentação oficial que especifique que, ao usar o sinal -c , ele sempre produzirá a saída binária correta, mas parece uma suposição razoável a ser feita.

    
por 03.03.2016 / 11:32
0

Você pode usar split(1) . Isso criará vários arquivos, cada um correspondendo a uma fatia correta do arquivo.

Exemplo: FILE=test ; split -b 1000 $FILE $FILE.split. criará arquivos de 1000 bytes test.split.aa e test.split.ab e assim por diante, e cat $FILE.split.* > $FILE.recompose produzirá um $ FILE.recompose idêntico ao $ FILE original. Se o seu arquivo for maior que 1000 * 26 * 26, você precisará aumentar o comprimento do sufixo (veja man split )

Com split -l 100 , colocará 100 linhas por arquivo. Estou bastante confiante de que isso será correto em bytes.

    
por 03.03.2016 / 20:32