MIT2020 Cram School- (4) Recopilación de datos

Convierta datos de un formato a otro

Específicamente, ya sea formato de texto o formato binario, los datos deben procesarse hasta que se obtengan los datos requeridos.

En conferencias anteriores, hemos visto algunos debates sobre datos básicos. Casi cada vez |que se utiliza un operador, se realiza algún tipo de contención de datos. Considere journalctl | grep-i inteluna orden como esta. Busca todas las entradas de registro del sistema mencionadas por Intel (no distingue entre mayúsculas y minúsculas). Es posible que no lo considere datos en espiral, pero está cambiando de un formato (todo el registro del sistema) a un formato que le sea más útil (solo entradas de registro de Intel). La mayoría de los debates sobre datos tratan de saber qué herramientas puede usar y cómo combinarlas.

Comencemos desde el principio. Para ordenar los datos, necesitamos dos cosas: ** los datos que se ordenarán y los relacionados con ellos. ** Los registros suelen ser un buen caso de uso, ya que a menudo desea investigar cosas sobre ellos, y leer todo esto no es factible. Determinemos quién intentó iniciar sesión en mi servidor viendo el registro de mi servidor:

ssh myserver journalctl

Lo restringimos a ssh:

ssh myserver journalctl | grep sshd

¡Tenga en cuenta que estamos usando tuberías para greptransferir archivos remotos en la computadora local ! sshEs sorprendente, lo discutiremos más a fondo en la próxima conferencia sobre el entorno de línea de comandos. Pero esto es mucho más de lo que queremos. Y es difícil de leer. Hagámoslo mejor:

ssh myserver 'journalctl | grep sshd | grep "Disconnected from"' | less

¿Por qué necesitas referencias adicionales? Bueno, nuestro registro puede ser grande, y es un desperdicio transmitirlo todo a nuestra computadora y luego filtrarlo. En cambio, podemos filtrar en el servidor remoto y luego usar los datos localmente. lessDanos un "localizador" que nos permita desplazarnos hacia arriba y hacia abajo en una salida larga. Para ahorrar algo de tráfico adicional al depurar la línea de comandos, incluso podemos pegar los registros actualmente filtrados en un archivo para que no tengamos que acceder a la red durante el desarrollo:

$ ssh myserver 'journalctl | grep sshd | grep "Disconnected from"' > ssh.log
$ less ssh.log

Todavía hay mucho ruido aquí. Hay muchas maneras de resolver este problema, pero vamos a ver una de las herramientas más poderosas en la caja de herramientas: sed.

sedEs un "editor de flujo", está construido sobre el antiguo ededitor. En él, básicamente le da un breve comando sobre cómo modificar el archivo en lugar de manipular directamente su contenido (aunque puede hacer lo mismo). Hay muchos comandos, pero uno de los comandos más comunes es s: sustitución. Por ejemplo, podemos escribir:

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed 's/.*Disconnected from //'

Lo que acabamos de escribir es una expresión regular simple; una construcción poderosa que le permite unir texto con patrones. sEl formato del comando es :, s/REGEX/SUBSTITUTION/dónde REGEXestá la expresión regular que se buscará y el SUBSTITUTIONtexto que se reemplazará con el texto correspondiente.

Expresión regular

Las expresiones regulares son muy comunes y útiles, por lo que vale la pena tomarse un tiempo para comprender cómo funcionan. Veamos el uso de las anteriores: /.*Disconnected from /. Las expresiones regulares están generalmente (aunque no siempre) /rodeadas. La mayoría de los caracteres ASCII solo tienen su significado normal, pero algunos caracteres tienen un comportamiento de coincidencia "especial". Es una pregunta muy frustrante qué personajes hacen cosas diferentes entre diferentes implementaciones de expresiones regulares. Los patrones muy comunes son:

. Significa "cualquier carácter individual" excepto nueva línea

* Cero o más partidos

+ Uno o más partidos anteriores

[abc] a, bY ccualquiera de los personajes

(RX1 | RX2)Con RX1o RX2cosas partidos

^ Comienzo de linea

$ Fin de línea

sedLas expresiones regulares son algo extrañas, y debe agregar una antes de la mayoría de las expresiones regulares \para darles un significado especial. O puedes pasar -E.

Entonces, mirando hacia atrás /*Disconnected from/, encontraremos que coincide con cualquier texto que comience con cualquier número de caracteres, seguido de la cadena de texto " Disconnected from". Esto es lo que queremos. Pero tenga en cuenta que las expresiones regulares son triples. ¿Qué sucede si alguien intenta Disconnected frominiciar sesión con el nombre de usuario " "? Tendremos:

Jan 17 03:13:00 thesquareplanet.com sshd[2631]: Disconnected from invalid user Disconnected from 46.97.239.16 port 55920 [preauth]

¿Qué obtendremos al final? Bueno, *y +por defecto es "codicioso". Emparejarán la mayor cantidad de texto posible. Obtendremos:

46.97.239.16 port 55920 [preauth]

Esto puede no ser lo que queremos. En algunas implementaciones de expresiones regulares, puede agregarlas *o +después de ellas para que no sean codiciosas, pero lamentablemente no es compatible con esto. Sin embargo, podemos cambiar al modo de línea de comando de perl, que admite la siguiente estructura:

perl -pe 's/.*?Disconnected from //'

Seguiremos usándolo a continuación sed, porque es una herramienta más común en estos trabajos. sedTambién puede hacer otras cosas convenientes, como imprimir líneas después de una coincidencia determinada, realizar múltiples reemplazos por llamada, buscar contenido, etc., pero no los presentaremos demasiado aquí. sedBásicamente es un tema completo en sí mismo, pero generalmente hay mejores herramientas.

De acuerdo, tenemos otro sufijo para eliminar. Que debemos hacer Hacer coincidir solo el texto después del nombre de usuario es un poco complicado, ¡especialmente si el nombre de usuario puede tener espacios o algo así! Lo que debemos hacer es unir toda la serie:

| sed -E 's/.*Disconnected from (invalid |authenticating )?user .* [^ ]+ port [0-9]+( \[preauth\])?$//'

Veamos qué está pasando con el depurador de expresiones regulares. Bueno, el comienzo es el mismo que antes. Luego, hacemos coincidir cualquier variable de "usuario" (hay dos prefijos en el registro). Luego hacemos coincidir cualquier cadena donde esté el nombre de usuario. Luego hacemos coincidir cualquier palabra individual ( [^]+; cualquier secuencia de caracteres no vacíos sin espacio). Luego está la palabra "puerto" seguida de una serie de números. Entonces puede ser el sufijo [preauth], luego el final de la línea.

Tenga en cuenta que con esta técnica, el nombre de usuario de "Desconectado de" ya no nos confundirá. ¿Sabes por qué?

Pero hay un problema, es decir, todo el registro se vacía. Después de todo, queremos mantener el nombre de usuario. Para esto, podemos usar "grupos de captura". Cualquier texto que coincida con la expresión regular rodeada de paréntesis se almacena en el grupo de captura numerado. Estos están disponibles en el reemplazo (en algunos motores, ¡incluso en el patrón mismo!) Como " \1", " \2", " \3", etc.

| sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'

Volver al debate de los datos.

Ok, ahora tenemos

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'

sedPuede hacer otras cosas interesantes, como inyectar texto (usando icomandos), imprimir explícitamente líneas (usando pcomandos), seleccionar líneas por índice y muchas otras cosas (usar man sedpara ver).

De todos modos Ahora proporcionamos una lista de todos los nombres de usuario que intentaron iniciar sesión. Pero esto no es útil. Echemos un vistazo a los comunes:

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'
 | sort | uniq -c

sortEl tipo de entrada . uniq -cPara la misma fila se pliega en una línea continua, y el número de ocurrencias en el prefijo . También podemos ordenarlo, manteniendo solo los nombres de inicio de sesión más comunes:

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'
 | sort | uniq -c
 | sort -nk1,1 | tail -n10

sort -nEl numérica (en lugar de diccionario) orden de clasificación . -k1,1Significa ** "Ordenar solo por la columna separada por el primer espacio" . ,nParcialmente significa "ordenar por el enésimo campo, el valor predeterminado es el final de la línea **. En este ejemplo en particular, ordenar por la línea completa no es importante, ¡pero estamos aquí para aprender!

Si queremos lo menos común, podemos usarlo en su headlugar tail. Además sort -r, se ordena en orden inverso.

Ok, esto es genial, pero solo queremos dar el nombre de usuario, ¿tal vez no uno por línea?

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'
 | sort | uniq -c
 | sort -nk1,1 | tail -n10
 | awk '{print $2}' | paste -sd,

Vamos a empezar desde la pasta: se permite el uso de un determinado delimitador de un solo carácter (- d) seguidos combinación ( -s). Pero awk¿cómo se va?

awk-otro editor

awkEs un lenguaje de programación que es muy bueno para procesar secuencias de texto.

Primero, {print$2}que haces? Bueno, el awkprograma toma un patrón opcional más un bloque para explicar qué hacer si el patrón coincide con una línea dada. El patrón predeterminado (que utilizamos anteriormente) coincide con todas las líneas . En el bloque, $0el contenido establecido en toda la línea , $1en $nel enésimo campo establecido en la línea , está separado por separadores de campo (de forma predeterminada, los espacios se -Fcambian). En este ejemplo, queremos decir que para cada línea, imprima el contenido del segundo campo, ¡que resulta ser el nombre de usuario!

Veamos si podemos hacer algo nuevo y extraño. Vamos a contar la cantidad de nombres de usuario únicos que ccomienzan y eterminan con:

| awk '$1 == 1 && $2 ~ /^c[^ ]*e$/ { print $2 }' | wc -l

Hay muchas cosas para desmontar aquí. Primero, observe que ahora tenemos un patrón (en el {…}contenido anterior). El patrón indica que el primer campo de la línea debe ser igual a 1 (este es uniq -cel conteo), y el segundo campo debe coincidir con la expresión regular dada. El bloque simplemente dice que imprima el nombre de usuario. Luego usamos para wc -lcontar el número de filas en la salida.

Sin embargo, awkes un lenguaje de programación, ¿recuerdas?

BEGIN { rows = 0 }
$1 == 1 && $2 ~ /^c[^ ]*e$/ { rows += $1 }
END { print rows }

BEGINEs un patrón que coincide con el comienzo de la entrada ( ENDcoincide con el final). Ahora, cada fila de bloques solo agrega el recuento del primer campo (aunque siempre es 1 en este ejemplo), y luego lo imprimimos al final. De hecho, podemos estar completamente libre grepy sed, debido a awkque puede hacerlo todo.

Analiza los datos

¡Puedes hacer cálculos! Por ejemplo, agregue los números en cada línea:

| paste -sd+ | bc -l

O produzca una expresión más detallada:

echo "2*($(data | paste -sd+))" | bc -l

Puede obtener datos de muchas maneras. stMuy ordenado, pero si ya tienes R:

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'
 | sort | uniq -c
 | awk '{print $1}' | R --slave -e 'x <- scan(file="stdin", quiet=TRUE); summary(x)'

R es otro lenguaje de programación, bueno en análisis de datos y dibujo. No discutiremos demasiados detalles, pero se puede decir que summaryimprime estadísticas de resumen sobre la matriz, calculamos una matriz a partir de la secuencia de entrada de números, por lo que R da las estadísticas que queremos.

Si solo quieres algunos dibujos simples, gnuplotsé tu amigo:

ssh myserver journalctl
 | grep sshd
 | grep "Disconnected from"
 | sed -E 's/.*Disconnected from (invalid |authenticating )?user (.*) [^ ]+ port [0-9]+( \[preauth\])?$/\2/'
 | sort | uniq -c
 | sort -nk1,1 | tail -n10
 | gnuplot -p -e 'set boxwidth 0.5; plot "-" using 1:xtic(2) with boxes'

A veces, desea organizar sus datos para poder encontrar contenido para instalar o eliminar según algunas listas largas. La recopilación de datos + que hemos discutido hasta ahora xargspuede ser una combinación poderosa:

rustup toolchain list | grep nightly | grep -vE "nightly-x86" | sed 's/-x86.*//' | xargs rustup toolchain uninstall

Organizar datos binarios.

Hasta ahora, hemos discutido principalmente la recopilación de datos de texto, pero las canalizaciones también son útiles para datos binarios. Por ejemplo, podemos usar ffmpeg para capturar una imagen de una cámara, convertirla a escala de grises, comprimirla, enviarla a través de SSH a una computadora remota, descomprimirla allí, hacer una copia y luego mostrarla.

ffmpeg -loglevel panic -i /dev/video0 -frames 1 -f image2 -
 | convert - -colorspace gray -
 | gzip
 | ssh mymachine 'gzip -d | tee copy.jpg | env DISPLAY=:0 feh -'
Publicado 28 artículos originales · ganado elogios 2 · Vistas 3259

Supongo que te gusta

Origin blog.csdn.net/Maestro_T/article/details/104355732
Recomendado
Clasificación