4 votos

BASH Script se bloquea después de algún procesamiento en Ubuntu

He estado corriendo por debajo de secuencia de comandos en un servidor de Red Hat, y funciona bien y termina el trabajo. El archivo que le estoy dando, contiene la mitad de un millón de líneas (aproximadamente 500000 líneas), y por eso (para terminar más rápido) he añadido un '&' al final del bucle while bloque

Pero ahora tengo la instalación de un equipo de Sobremesa con 8 GB de RAM corriendo Ubuntu 18.04 en él, y la ejecución del mismo código, sólo los acabados de unos pocos miles de líneas y, a continuación, se bloquea. He leído un poco sobre ello y aumentó el límite de la pila a un número ilimitado así y todavía se colgó después de 80000 líneas o así, Cualquier sugerencia acerca de cómo se puede optimizar el código o afinar mi PC parámetros para siempre terminar el trabajo?

while read -r CID60
do    
 { 
       OLT=$(echo "$CID60" | cut -d"|" -f5) 
       ONID=${OLT}:$(echo "$CID60" | cut -d, -f2 | sed 's/ //g ; s/).*|//') 
       echo $ONID,$(echo "$CID60" | cut -d"|" -f3) >> $localpath/CID_$logfile.csv       
  } &     
done < $localpath/$CID7360

Entrada:

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN45| Unlocked|12-654-0330|Up|202-00_MSRFKH00OL6|P282018767.C2028 ( network, R1.S1.LT7.PON8.ONT81.SERV1 )|

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN46| Unlocked|12-654-0330|Down|202-00_MSRFKH00OL6|P282017856.C881 ( local, R1.S1.LT7.PON8.ONT81.C1.P1 )|

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN52| Unlocked|12-664-1186|Up|202-00_MSRFKH00OL6|P282012623.C2028 ( network, R1.S1.LT7.PON8.ONT75.SERV1 )|

salida:

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186

mi salida de interés es el 5 de columna ( separados con pipe | ) se concatenan con la parte de la última columna y, a continuación, la tercera columna

5voto

xenoid Puntos 146

Una solución sed pura:

 sed -r 's/^[^|]+\|[^|]+\|([^|]+)\|[^|]+\|([^|]+)\|.+\( .+, ([^ ]+).+/\2:\3,\1/' <in.dat >out.dat
 

5voto

Ole Tange Puntos 197
doit() {
  # Hattip to @sudodus
  tr ' ' '|' |
    tr -s '|' '|' |
    cut -d '|' -f 3,5,9 
}
export -f doit
parallel -k --pipepart --block -1 -a input.txt doit > output.txt
  • -k mantener el orden, así que la primera/última línea de la entrada también será la primera/última línea de la salida
  • --pipepart divide el archivo en la marcha
  • --block -1 de 1 pedazo por CPU hilo
  • -a input.txt el archivo a dividir
  • doit el comando (o función bash) para llamar

Speedwise la parallel (amarillo) versión supera a la tr (negro) alrededor de 200 MB en mi sistema (Segundos vs MB):

graph

3voto

Rufo Puntos 121

Oneliners por mí y a otras personas, así como algunas secuencias de comandos de prueba

Si el orden de los elementos y los separadores pueden ser diferentes de lo que se especifica en la pregunta, pensé que el siguiente one-liner haría,

< input tr ' ' '|' | cut -d '|' -f 4,6,10 > output

pero en un comentario que escribió que usted necesita exactamente con el formato especificado.

He añadido una solución con 'awk', que está aproximadamente a la par con PerlDuck la solución de con perl. Ver el final de esta respuesta.

< input awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > output

Prueba de oneliners y pequeñas secuencias de comandos

La prueba fue hecha en mi equipo con Lubuntu 18.04.1 LTS, 2*2 procesadores y 4 GiB de RAM.

Me hizo un gran infile 'doblando 20 veces" de su demo input (1572864 líneas), por lo que algunos margen de su 500000 líneas,

Oneliner con cut y sed:

$ < infile cut -d '|' -f 3,5,6 | sed -e 's/|[A-Z].*, /|/' -e 's/ )$//' > outfile
$ wc -l infile
1572864 infile
$ wc -l outfile
1572864 outfile
$ tail outfile
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1

Temporización

Podemos esperar, que un puro sed solución sería más rápido, pero creo que la reordenación de los datos ralentiza, por lo que el cut y sed solución es más rápido. Ambas soluciones funcionan sin ningún problema en mi ordenador.

Oneliner con cut y sed:

$ time < infile cut -d '|' -f 3,5,6 | sed -e 's/|[A-Z].*, /|/' -e 's/ )$//' > outfile

real    0m8,132s
user    0m8,633s
sys     0m0,617s

Un puro sed oneliner por xenoid:

$ time sed -r 's/^[^|]+\|[^|]+\|([^|]+)\|[^|]+\|([^|]+)\|.+\( .+, ([^ ]+).+/\2:\3,\1/' <infile > outfile-sed 

real    1m8,686s
user    1m8,259s
sys     0m0,344s

Un python script usando una expresión regular con la que no codicioso partidos por xeniod:

#!/usr/bin/python

import sys,re

pattern=re.compile(r'^[^|]+?\|[^|]+?\|([^|]+?)\|[^|]+?\|([^|]+?)\|[^,]+?, (.+) \)\|$')

for line in sys.stdin:
    match=pattern.match(line)
        if match:
            print(match.group(2)+':'+match.group(3)+','+match.group(1))

$ time < infile ./python-ng > outfile.pyng

real    0m8,055s
user    0m7,359s
sys 0m0,300s

$ python --version
Python 2.7.15rc1

Un perl oneliner por PerlDuck es más rápido que el anterior oneliners:

$ time perl -lne 'print "$2:$3,$1" if /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/;' < infile > outfile.perl

real    0m5,929s
user    0m5,339s
sys     0m0,256s

Oneliner con tr y cut con un tr -s comando:

Yo solía tr a convertir los espacios en el archivo de entrada a la canalización de los caracteres y, a continuación, cut podría hacerlo todo sin sed. Como se puede ver, tr es mucho más rápido que sed. El tr -s comando elimina la doble tubos en la entrada, que es una buena idea, especialmente si no se puede repetir espacios o tuberías en el archivo de entrada. No cuesta mucho.

$ time < infile tr ' ' '|' | tr -s '|' '|' | cut -d '|' -f 3,5,9 > outfile-tr-cut

real    0m1,277s
user    0m1,781s
sys     0m0,925s

Oneliner con tr y cut sin tr -s comando, el más rápido hasta el momento:

time < infile tr ' ' '|' | cut -d '|' -f 4,6,10 > outfile-tr-cut

real    0m1,199s
user    0m1,020s
sys     0m0,618s


$ tail outfile-tr-cut
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1

Oneliner con awk, rápido, pero no el más rápido,

< input awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > output

$ time < infile awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > outfile.awk

real    0m5,091s
user    0m4,724s
sys     0m0,365s

awk con parallel implementado de acuerdo a Ole Tange reduce el tiempo real de 5s a 2s:

#!/bin/bash

doit() {
 awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}'
}
export -f doit
parallel -k --pipepart --block -1 -a infile doit > outfile.parallel-awk

$ time ./parallel-awk 
# Academic tradition requires you to cite works you base your article on.
# When using programs that use GNU Parallel to process data for publication
#please cite:

#  O. Tange (2011): GNU Parallel - The Command-Line Power Tool,
#  ;login: The USENIX Magazine, February 2011:42-47.

# This helps funding further development; AND IT WON'T COST YOU A CENT.
#If you pay 10000 EUR you should feel free to use GNU Parallel without citing.

# To silence this citation notice: run 'parallel --citation'.

real    0m1,994s
user    0m5,015s
sys     0m0,984s

Podemos esperar que la ventaja parallel aumentará con el tamaño más grande de el archivo de entrada como se describe en el diagrama en la Ola Tange la respuesta a esta pregunta.

La velocidad de resumen: el 'real' tiempo de acuerdo a time redondeado a 1 decimal

1m 8.7s - sed
   8.1s - cut & sed
   7.4s - python
   5.9s - perl
   5.1s - awk
   2.0s - parallel & awk
   1.2s - tr & cut

Por último, debo señalar que la oneliners con sed, python, perl, awk y {parallel & awk} crear un archivo de salida con el formato prescrito.

$ tail outfile.awk
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186

3voto

Mike Puntos 1

Solución perl

Este script no hace nada en paralelo, pero es bastante rápido independientemente. Guárdelo como filter.pl (o el nombre que prefiera) y conviértalo en ejecutable.

 #!/usr/bin/env perl

use strict;
use warnings;

while( <> ) {
    if ( /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/ ) {
        print "$2:$3,$1\n";
    }
}
 

Copié sus datos de muestra hasta que obtuve 1,572,864 líneas y luego las ejecuté de la siguiente manera:

 me@ubuntu:~> time ./filter.pl < input.txt > output.txt
real    0m3,603s
user    0m3,487s
sys     0m0,100s

me@ubuntu:~> tail -3 output.txt
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
 

Si prefieres una sola línea, haz:

 perl -lne 'print "$2:$3,$1" if /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/;' < input.txt > output.txt
 

2voto

xenoid Puntos 146

Pitón

 import sys,re

pattern=re.compile(r'^.+\|.+\|(.+)\|.+\|(.+)\|.+, (.+) \)\|$')

for line in sys.stdin:
match=pattern.match(line)
if match:
    print(match.group(2)+':'+match.group(3)+','+match.group(1))
 

(funciona con Python2 y Python3)

Usar una expresión regular con coincidencias no codiciosas es 4 veces más rápido (¿evita retroceder?) Y pone a Python a la par con el método cortar / sed (python2 es un poco más rápido que python3)

 import sys,re

pattern=re.compile(r'^[^|]+?\|[^|]+?\|([^|]+?)\|[^|]+?\|([^|]+?)\|[^,]+?, (.+) \)\|$')

for line in sys.stdin:
match=pattern.match(line)
if match:
    print(match.group(2)+':'+match.group(3)+','+match.group(1))
 

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: