líneas de recuento sed entre patrones: varios archivos

líneas de recuento sed entre patrones: varios archivos

Tengo varios .txtarchivos en un directorio. Cada archivo tiene una sección:

DONE
item 1
item 2
item 3
DONE

Me gustaría contar el número de líneas entre los dos DONEmarcadores para cada archivo por separado.

solíaesta preguntapara crear esto:

sed -n "/DONE/,/DONE/ p" *.txt | wc -l > ~/word_count.txt

Pero esto combina los recuentos de cada archivo en un solo número. En lugar de eso, me gustaría obtener resultados como este:

file1.txt 3
file2.txt 5
file3.txt 6

Respuesta1

Mejor uso awkparacontar.

awk '
  FNR == 1 {inside = 0}
  $0 == "DONE" {
    if (inside) print FILENAME, n
    n = 0
    inside = ! inside
    next
  }
  inside {n++}' ./*.txt

Eso imprimirá un registro para cada DONE...DONEsección de cada archivo, lo que significa que no se imprimirá nada si no existe dicha sección. Para imprimirlos 0, necesitaría la implementación GNU de awkcon sus BEGINFILEdeclaraciones ENDFILEespeciales:

awk '
  BEGINFILE {DONE_count = 0}
  $0 == "DONE" {
    if (++DONE_count % 2 == 0) print FILENAME, n
    n = 0
    next
  }
  DONE_count % 2 {n++}
  ENDFILE {if (!DONE_count) print FILENAME, 0}' ./*.txt

O ejecute uno awkpor archivo:

for file in ./*.txt; do
  awk '
    $0 == "DONE" {
      if (++DONE_count % 2 == 0) print FILENAME, n
      n = 0
      next
    }
    DONE_count % 2 {n++}
    END {if (!DONE_count) print FILENAME, 0}' "$file"
done

Respuesta2

perl -lne '
   eof and !$a && print "$ARGV: ", 0+$a;          # no DONEs => ans=0
   next unless /DONE/ && !$a ... /DONE/;          # skip non-DONE ranges
   /DONE/ and !$a++ && next;                      # begin DONE range
   !/DONE/ and !eof and $a++,next;                # middle of DONE range
   !/DONE/ and eof and $a=2;                      # lone DONE => ans=0
   print "$ARGV: ", ($a-2, $a=0, close ARGV)[0];  # end of DONE range
                                                  # at the end we do 4 things: 1) subtract 2 from sum, 2) print filename+sum, 3) reset sum, and 4) skip the current file and jump to the next file in queue.
' ./*.txt

Con sedpodemos hacer esto por archivo:

for f in ./*.txt; do
   printf '%s: %d\n' "$f" "$(sed -e '/DONE/,/DONE/!d; //d' "$f" | wc -l)"
done

La diferencia estará en el escenario en el que no tendremos un cierre HECHO.

información relacionada