tutorial query puertos funciona documentacion como linux bash unix sed

linux - query - ¿Cómo usar sed para extraer líneas en el orden especificado?



logstash tutorial (3)

Tengo un archivo que tiene una longitud de ~ 50,000 líneas y necesito recuperar líneas específicas. He intentado el siguiente comando:

sed -n ''Np;Np;Np'' inputFile.txt > outputFile.txt

(''N'' son las líneas específicas, quiero extraer)

Esto funciona bien, pero el comando extrae las líneas en ORDEN (es decir, PIDE PEDIDOS mi entrada) ej. si lo intento

sed -n ''200p;33p;40,000p'' inputFile.txt > outputFile.txt

Recibo un archivo de texto con las líneas ordenadas como: 33, 200, 40,000 (lo cual no funciona para mi propósito). ¿Hay alguna manera de mantener el orden en que aparecen las líneas en el comando?


¿Puedes usar también otros comandos de bash? En ese caso esto funciona:

for i in 200 33 40000; do sed -n "${i}p" inputFile.txt done > outputFile.txt

Probablemente esto sea más lento que usar array dentro de sed, pero es más práctico.


Debe mantener la línea 33 hasta que haya visto la línea 200:

sed -n ''33h; 200{p; g; p}; 40000p'' file

Vea el manual para una explicación más detallada: https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html

awk podría ser más legible:

awk '' NR == 33 {line33 = $0} NR == 200 {print; print line33} NR == 40000 {print} '' file

Si tiene un número arbitrario de líneas para imprimir en un orden específico, puede generalizar esto:

awk -v line_order="11 3 5 1" '' BEGIN { n = split(line_order, inorder) for (i=1; i<=n; i++) linenums[inorder[i]] } NR in linenums {cache[NR]=$0} END {for (i=1; i<=n; i++) print cache[inorder[i]]} '' file


con perl , guarda las líneas de entrada en la variable hash con el número de línea como clave

$ seq 12 20 | perl -nle '' @l = (5,2,3,1); $a{$.} = $_ if( grep { $_ == $. } @l ); END { print $a{$_} foreach @l } '' 16 13 14 12

  • $. es el número de línea y grep { $_ == $. } @l grep { $_ == $. } @l verifica si ese número de línea está presente en la matriz @l que contiene las líneas deseadas en el orden requerido


como una sola @l , @l declaración dentro de BEGIN para evitar la inicialización en cada iteración y también para garantizar que no haya líneas en blanco si el número de línea está fuera de rango:

$ seq 50000 > inputFile.txt $ perl -nle ''BEGIN{@l=(200,33,40000)} $a{$.}=$_ if(grep {$_ == $.} @l); END { $a{$_} and print $a{$_} foreach (@l) }'' inputFile.txt > outputFile.txt $ cat outputFile.txt 200 33 40000

Para entradas suficientemente pequeñas, puede guardar las líneas en una matriz e imprimir los índices necesarios. Tenga en cuenta que el ajuste realizado como índice comienza con 0

$ seq 50000 | perl -e ''$l[0]=0; push @l,<>; print @l[200,33,40000]'' 200 33 40000


Solución con combo head y tail :

$ for i in 200 33 40000; do head -"${i}" inputFile.txt | tail -1 ; done 200 33 40000


Comparación de rendimiento para el archivo de entrada seq 50000 > inputFile.txt

$ time perl -nle ''BEGIN{@l=(200,33,40000)} $a{$.}=$_ if(grep {$_ == $.} @l); END { $a{$_} and print $a{$_} foreach (@l) }'' inputFile.txt > outputFile.txt real 0m0.044s user 0m0.036s sys 0m0.000s $ time awk -v line_order="200 33 40000" '' BEGIN { n = split(line_order, inorder) for (i=1; i<=n; i++) linenums[inorder[i]] } NR in linenums {cache[NR]=$0} END {for (i=1; i<=n; i++) print cache[inorder[i]]} '' inputFile.txt > outputFile.txt real 0m0.019s user 0m0.016s sys 0m0.000s $ time for i in 200 33 40000; do sed -n "${i}{p;q}" inputFile.txt ; done > outputFile.txt real 0m0.011s user 0m0.004s sys 0m0.000s $ time sed -n ''33h; 200{p; g; p}; 40000p'' inputFile.txt > outputFile.txt real 0m0.009s user 0m0.008s sys 0m0.000s $ time for i in 200 33 40000; do head -"${i}" inputFile.txt | tail -1 ; done > outputFile.txt real 0m0.007s user 0m0.000s sys 0m0.000s