Bash: Conte N caracteres dentro de vários arquivos ordenados alfabeticamente

1

Eu trabalho com um revisor a quem pago certa soma por cada N caracteres (como 500.000). Ele (geralmente) cria / edita arquivos em ordem alfabética. Conteúdo / nomes de arquivos estão em (não latinos) utf-8. Arquivos de marcação de texto simples (.md) ou org (.org).

Eu preciso encontrar uma maneira eficiente de observar por mim mesmo os "marcos dos personagens N", para que eu saiba quando pagá-lo. Por exemplo, digamos que eu paguei a ele pela última vez até o número do personagem 3036 no arquivo "aab.md". Ele terminou esse arquivo, continuou com "aac.md", "aad.md" e agora está em "csdw.md".

  1. Como posso "medir" N caracteres (tudo incluído: pontuação, espaços, dígitos, novas linhas, chaves, etc) dentro desse fluxo (supondo que todos eles residem no mesmo diretório)? Ou seja Eu preciso de um comando bash que irá obter "aab.md", 3036 e N como entrada e fornecer algo como: "csaw.md", 5023 (significando que N caracteres terminaram nesse arquivo nessa letra exata).
  2. Como posso listar os arquivos que foram contabilizados no comando anterior?
  3. É menos importante, mas se possível - como será o comando do # 1, se os arquivos estiverem espalhados por vários diretórios (também em ordem alfabética), como se ele tivesse parado da última vez no caractere 3036 no arquivo "a /aab.md "e agora está em" np / csdw.md "?

Eu descobri que cat * | wc -m pode fornecer quantidade de caracteres em todos os arquivos, mas ainda está longe do que eu preciso.

    
por user1876484 06.11.2018 / 11:25

1 resposta

3

Vou sugerir o uso de zsh em vez de bash , o que facilitará a obtenção de uma lista recursiva classificada dos novos arquivos desde aab.md .

#! /bin/zsh -
last_file=aab.md offset_in_last_file=3036 n=500000
new_files=(**/*.(md|org)(N))
new_files=($new_files[(Re)$last_file,-1])

(($#new_files)) && perl -Ci -sne '
   $l = length; $go += $l; $o += $l;
   if ($go >= $n) {
     printf qq(file="%s", line=%d, char-offset=%d\n), $ARGV, $., $o + $n - $go;
     exit;
   }
   $o = 0 if eof' -- -go=-$offset_in_last_file -n=$n ./$^new_files

Para o número de clusters de grafema em vez de caracteres, substitua $l = length por $l = () = /\X/g . Por exemplo, é escrito como U+0065U+0301 é um cluster de grafema expresso com dois caracteres (e 3 bytes em UTF-8), enquanto é um cluster de grafema e um caractere (e 2 bytes) quando escrito como U + 00E9.

Com o bash 4.4+ e o GNU awk , você poderia fazer algo semelhante para construir o array $new_files com

shopt -s nullglob extglob globstar
readarray -td '' new_files < <(
    printf '%s
#! /bin/zsh -
last_file=aab.md offset_in_last_file=3036 n=500000
new_files=(**/*.(md|org)(N))
new_files=($new_files[(Re)$last_file,-1])

(($#new_files)) && perl -Ci -sne '
   $l = length; $go += $l; $o += $l;
   if ($go >= $n) {
     printf qq(file="%s", line=%d, char-offset=%d\n), $ARGV, $., $o + $n - $go;
     exit;
   }
   $o = 0 if eof' -- -go=-$offset_in_last_file -n=$n ./$^new_files
' **/*.@(md|org) | L=$last_file awk -v RS='
shopt -s nullglob extglob globstar
readarray -td '' new_files < <(
    printf '%s%pre%' **/*.@(md|org) |
      L=$last_file awk -v RS='%pre%' -v ORS='%pre%' '$0 == ENVIRON["L"], 0'
  )
' -v ORS='%pre%' '$0 == ENVIRON["L"], 0' )

Com bash , você também precisa substituir ./$^new_files por "${new_files[@]/#/.\/}" . (Estamos adicionando um prefixo ./ para evitar problemas com nomes de arquivos que começam com - ou | , < , > , whitespace ...

    
por 06.11.2018 / 12:12

Tags