AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 459521
Accepted
Pitel
Pitel
Asked: 2018-07-31 22:35:20 +0800 CST2018-07-31 22:35:20 +0800 CST 2018-07-31 22:35:20 +0800 CST

Como truncar o arquivo para o número máximo de caracteres (não bytes)

  • 772

Como posso truncar um arquivo de texto (codificado em UTF-8) para um determinado número de caracteres? Eu não me importo com comprimentos de linha e o corte pode ser no meio da palavra.

  • cutparece operar em linhas, mas eu quero um arquivo inteiro.
  • head -cusa bytes, não caracteres.
text-processing
  • 3 3 respostas
  • 2271 Views

3 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-07-31T23:23:52+08:002018-07-31T23:23:52+08:00

    Alguns sistemas têm um truncatecomando que trunca os arquivos em um número de bytes (não caracteres).

    Não conheço nenhum que seja truncado para vários caracteres, embora você possa recorrer ao perlque está instalado por padrão na maioria dos sistemas:

    perl

    perl -Mopen=locale -ne '
      BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
    
    • Com -Mopen=locale, usamos a noção de localidade de quais são os caracteres (portanto, em localidades usando o conjunto de caracteres UTF-8, são caracteres codificados em UTF-8). Substitua por -CSse desejar que a E/S seja decodificada/codificada em UTF-8, independentemente do conjunto de caracteres da localidade.

    • $/ = \1234: definimos o separador de registro para uma referência a um inteiro que é uma maneira de especificar registros de comprimento fixo (em número de caracteres ).

    • então, ao ler o primeiro registro, truncamos stdin no lugar (portanto, no final do primeiro registro) e saímos.

    GNU sed

    Com GNU sed, você poderia fazer (assumindo que o arquivo não contém caracteres NUL ou sequências de bytes que não formam caracteres válidos - ambos devem ser verdadeiros para arquivos de texto):

    sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
    

    Mas isso é muito menos eficiente, pois ele lê o arquivo inteiro e o armazena inteiro na memória e grava uma nova cópia.

    GNU awk

    O mesmo com GNU awk:

    awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
    
    • -e code -E /dev/null "$file"sendo uma maneira de passar nomes de arquivos arbitrários paragawk
    • RS='^$': modo slurp .

    Shell integrado

    Com ksh93, bashou zsh(com shells diferentes de zsh, assumindo que o conteúdo não contém bytes NUL):

    content=$(cat < "$file" && echo .) &&
      content=${content%.} &&
      printf %s "${content:0:1234}" > "$file"
    

    Com zsh:

    read -k1234 -u0 s < $file &&
      printf %s $s > $file
    

    Ou:

    zmodload zsh/mapfile
    mapfile[$file]=${mapfile[$file][1,1234]}
    

    Com ksh93ou bash(cuidado , é falso para caracteres de vários bytes em várias versões debash ):

    IFS= read -rN1234 s < "$file" &&
      printf %s "$s" > "$file"
    

    ksh93também pode truncar o arquivo no lugar em vez de reescrevê-lo com seu <>;operador de redirecionamento:

    IFS= read -rN1234 0<>; "$file"
    

    iconv + cabeça

    Para imprimir os primeiros 1234 caracteres, outra opção poderia ser converter para uma codificação com um número fixo de bytes por caractere como UTF32BE/ UCS-4:

    iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
    

    head -cnão é padrão, mas bastante comum. Um equivalente padrão seria, dd bs=1 count="$((1234 * 4))"mas seria menos eficiente, pois leria a entrada e escreveria a saída um byte por vez¹. iconvé um comando padrão, mas os nomes de codificação não são padronizados, então você pode encontrar sistemas semUCS-4

    Notas

    De qualquer forma, embora a saída tenha no máximo 1234 caracteres, pode acabar não sendo um texto válido, pois possivelmente terminaria em uma linha não delimitada.

    Observe também que, embora essas soluções não cortassem o texto no meio de um caractere, elas poderiam quebrá-lo no meio de um grafema , como a éexpresso como U+0065 U+0301 (a eseguido por um acento agudo combinado), ou grafemas de sílabas Hangul em suas formas decompostas.


    ¹ e na entrada do pipe você não pode usar bsvalores diferentes de 1 de forma confiável, a menos que você use a iflag=fullblockextensão GNU, como ddpoderia fazer leituras curtas se ele ler o pipe mais rápido do que iconvpreenchê-lo

    • 15
  2. Michael Ströder
    2018-07-31T23:01:03+08:002018-07-31T23:01:03+08:00

    Se você sabe que o arquivo de texto contém Unicode codificado como UTF-8, você precisa primeiro decodificar o UTF-8 para obter uma sequência de entidades de caracteres Unicode e dividi-las.

    Eu escolheria o Python 3.x para o trabalho.

    Com o Python 3.x, a função open() tem um argumento de palavra-chave extra encoding=para ler arquivos de texto . A descrição do método io.TextIOBase.read() parece promissora.

    Então, usando o Python 3, ficaria assim:

    truncated = open('/path/to/file.txt', 'rt', encoding='utf-8').read(1000)
    

    Obviamente, uma ferramenta real adicionaria argumentos de linha de comando, tratamento de erros, etc.

    Com o Python 2.x você pode implementar seu próprio objeto semelhante a um arquivo e decodificar o arquivo de entrada linha por linha.

    • 5
  3. confetti
    2018-08-01T08:41:20+08:002018-08-01T08:41:20+08:00

    Eu gostaria de adicionar outra abordagem. Provavelmente não é o melhor desempenho em termos de desempenho, e muito mais longo, mas fácil de entender:

    #!/bin/bash
    
    chars="$1"
    ifile="$2"
    result=$(cat "$ifile")
    rcount=$(echo -n "$result" | wc -m)
    
    while [ $rcount -ne $chars ]; do
            result=${result::-1}
            rcount=$(echo -n "$result" | wc -m)
    done
    
    echo "$result"
    

    Invoque-o com $ ./scriptname <desired chars> <input file>.

    Isso remove o último caractere um por um até que o objetivo seja alcançado, o que parece muito ruim em termos de desempenho, especialmente para arquivos maiores. Eu só queria apresentar isso como uma ideia para mostrar mais possibilidades.

    • 0

relate perguntas

  • Grep para um conjunto de linhas de $START a $END AND que contém uma correspondência em $MIDDLE

  • Reorganize as letras e compare duas palavras

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Embaralhamento de arquivo de várias linhas

  • como posso alterar o caso do caractere (de baixo para cima e vice-versa)? ao mesmo tempo [duplicado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve