¿Cómo seleccionar ciertas líneas (n, n + 4, n + 8, n + 12 ...) del archivo?


Respuestas:


28

Usando AWK:

awk '!((NR - 1) % 4)' input > output

Descubrir cómo funciona esto se deja como un ejercicio para el lector.


gracias por este corto curso awk!
darxmurf

20
NR % 4 == 1Sería más legible en mi opinión.
Stéphane Chazelas

12
De acuerdo @ Stéphane; esto es probablemente cuestionable por mi parte, pero para las preguntas de tarea potencialmente trato de ofuscar un poco mis respuestas ...
Stephen Kitt

@StephenKitt ofusca tus respuestas? De Verdad? Este no es el lugar para hacer eso.
datos

22

Usando split (GNU coreutils):

split -nr/1/4 input > output
  • -ngenerar CHUNKSarchivos de salida

y CHUNKScomo

  • r/K/N use la distribución round robin y solo envíe Kth of N a stdout sin dividir líneas / registros

1
Mente alucinada. Respuestas como esta son las razones por las que amo este SE. ¡Gracias!
user1717828

21

Con GNU sed:

sed '1~4!d' < input > output

Con estándar sed:

sed -n 'p;n;n;n' < input > output

Con 1y 4en $ny $ivariables:

sed "$n~$i!d" # GNU only
awk -v n="$n" -v i="$i" 'NR >= n && (NR % i) == (n % i)'

7

Agregando la solución perl obligatoria:

perl -ne 'print if $. % 4 == 1' input > output

4

Versión de Python, solo por diversión:

with open('input.txt') as f:
    for i, line in enumerate(f.readlines()):
        if i%4 == 0:
            print(line.strip())

enumerate(f)debería poder hacer el trabajo mientras consume menos memoria
iruvar

@iruvar ¡Eso es genial! Nunca me di cuenta de eso antes; se utilizará en el futuro. Siéntase libre de editarlo en esta respuesta; Realmente no voy a mantenerlo con optimizaciones ya que las otras respuestas de Bash (especialmente esta ) son definitivamente el camino a seguir.
user1717828

Si va a usar readlines(por lo tanto, arrastrando todo el archivo a la memoria), puede usarlo f.readlines()[::4]para obtener cada cuarta línea. Entonces puedes usar print(''.join(f.readlines()[::4])).
Nick Matteo

3

POSIX sed: este método utiliza el posixly sed y, por lo tanto, se puede ejecutar en todas partes, o al menos aquellos seds que respetan posixly.

 $ sed -ne '
   /\n/!{
    H;s/.*//;x
   }

   :loop
       $bdone
       N;s/\n/&/4
       tdone
   bloop

   :done
   s/.//;P
 ' input.file

Otra es una generación programática de código sed para fines de escalabilidad:

$ code=$(yes n | head -n 4 | paste -sd\; | sed s/n/p/)
$ sed -ne "$code" input.file

Perl: rellenamos la matriz A hasta que tenga un tamaño de 4. Luego imprimimos su primer elemento y también limpiamos la matriz.

$ perl -pe '
   $A[@A] = @A ? <> : $_ while @A < 4;
   $_ = (splice @A)[0];
' input.file

1

Llame con scriptname filename skip(4 en su caso) Funciona tirando iterlíneas desde la parte superior del archivo y luego solo genera la última. A continuación, incrementa iterpor skipsy se repite mientras el valor de iterno ha excedido el linesen file.

#!/bin/bash
file="$1"
lines=`wc -l < "$file"`
skips="$2" || "4"
iter=1
while [ "$iter" -le "$lines" ]; do
 head "$file" -n $iter | tail -n 1
 iter=$(( $iter + $skips ))
done

1

Golpe puro:

mapfile -t lines < input
for (( i=0; i < ${#lines[@]}; i+=4 ))
do printf "%s\n" "${lines[$i]}"
done

mapfile es un archivo incorporado en Bash 4 que lee la entrada estándar en una matriz, aquí llamada lines, con una línea por entrada. La -topción elimina las nuevas líneas finales.

Si desea imprimir cada cuarta línea a partir de la línea 4, puede hacerlo en un comando utilizando mapfilela opción de devolución de llamada -C, que ejecuta el código proporcionado cada tantas líneas, con el intervalo dado por -c. El índice de matriz actual y la siguiente línea a asignar se dan al código como argumentos.

mapfile -t -c4 -C 'printf "%.0s%s\n"' < input

Esto usa el printfincorporado; el código de formato %.0ssuprime el primer argumento (el índice), por lo que solo se imprime la línea.

Podría usar el mismo comando para imprimir cada cuarta línea a partir de la línea 1, 2 o 3, pero tendría que anteponer 3, 2 o 1 líneas inputantes de alimentarlo mapfile, lo que creo que es más problemático de lo que vale la pena. .

Esto también funciona:

mapfile -t lines < input
printf "%s%.0s%.0s%.0s\n" "${lines[@]}"

Aquí, printfconsume cuatro entradas de la matriz linesa la vez, solo imprime la primera y omite las otras tres con %.0s. No me gusta esto, ya que tienes que manipular manualmente la cadena de formato para diferentes intervalos o puntos de partida.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.