Uno de los primeros comandos de Linux que muchos administradores de sistemas aprenden es grep. Esta venerable herramienta ha existido durante décadas y es crucial para el cinturón de herramientas de cualquier administrador. El núcleo de Grep es simplemente la capacidad de buscar en texto plano un patrón RegEx. Grep puede buscar en los archivos de un directorio determinado o en la entrada de flujo para obtener coincidencias. ¿Sabías que PowerShell tiene grep? Bueno..casi.
PowerShell, al ser un lenguaje, es más que un binario de propósito único. Por lo tanto, ¿qué habilidades incorporadas existen para buscar texto plano utilizando patrones RegEx como lo hace grep? En este artículo exploramos las innumerables formas de buscar texto en archivos usando PowerShell.
Explorando el Cmdlet Select-String
Select-String (nuestro grep de PowerShell) trabaja en líneas de texto y por defecto buscará la primera coincidencia en cada línea y luego mostrará el nombre del archivo, el número de línea y el texto dentro de la línea coincidente. Además, Select-String puede trabajar con diferentes codificaciones de archivos, como el texto Unicode, mediante el uso de la marca de orden de bytes (BOM) para determinar el formato de codificación. Si falta la BOM, Select-String asumirá que es un archivo UTF8.
Parámetros de Select-String
-
AllMatches– Normalmente,Select-Stringsólo buscará la primera coincidencia en cada línea, utilizando este parámetro el cmdlet buscará más de una coincidencia. Se seguirá emitiendo un único objetoMatchInfopara cada línea, pero contendrá todas las coincidencias encontradas. -
CaseSensitive– Las coincidencias no distinguen entre mayúsculas y minúsculas por defecto, esto obliga al cmdlet a buscar coincidencias que coincidan exactamente con el patrón de entrada. -
Context– Un parámetro muy útil ya que, se puede definir el número de líneas antes y después de la coincidencia que se mostrará. Al añadir este parámetro se modifica el objetoMatchInfoemitido para incluir una nueva propiedadContextque contiene las líneas especificadas.
Tenga en cuenta que si canaliza la salida de
Select-Stringa otra llamadaSelect-String, el contexto no estará disponible ya que sólo se busca en la única propiedad resultanteMatchInfoline.
-
Culture– Utilizado con el parámetroSimpleMatch, especifica una cultura que debe coincidir con el patrón especificado. Esto incluye opciones comoen-USes, ofr-FRcomo ejemplos. Otras opciones útiles son las opcionesOrdinalyInvariantOrdinales para comparaciones binarias no lingüísticas yInvariantes para comparaciones independientes de la cultura.
Este parámetro se introdujo en PowerShell 7 y no está disponible para versiones anteriores. También hay que tener en cuenta que esto utilizará la cultura actual del sistema, por defecto, que se puede encontrar utilizando
Get-Culture.
-
Encoding– Especifica la codificación del archivo de destino a buscar, que por defecto esutf8NoBOM.-
ascii: Utiliza la codificación para el conjunto de caracteres ASCII (7 bits). -
bigendianunicode: Codifica en formato UTF-16 utilizando el orden de bytes big-endian. -
oem: Utiliza la codificación por defecto para MS-DOS y programas de consola. -
unicode: Codifica en formato UTF-16 utilizando el orden de bytes little-endian. -
utf7: codifica en formato UTF-7. -
utf8: codifica en formato UTF-8. -
utf8BOM: Codifica en formato UTF-8 con marca de orden de bytes (BOM) -
utf8NoBOM: Codifica en formato UTF-8 sin marca de orden de bytes (BOM) -
utf32: Codifica en formato UTF-32.
A partir de PowerShell Core 6.2, el parámetro
Encodingtambién acepta IDs numéricos de páginas de código registradas como1251o nombres de cadena comowindows-1251. -
A partir de PowerShell Core 6.2, el parámetro
Encodingtambién acepta IDs numéricos de páginas de código registradas como1251o nombres de cadena comowindows-1251.
-
Exclude– Trabajando con el parámetroPath, excluye elementos específicos utilizando un patrón, como*.txt. -
Include– Al igual que el parámetroExcludeIncludeincluirá sólo los elementos especificados utilizando un patrón, como*.log. -
List– Sólo devuelve la primera instancia de texto coincidente de cada archivo de entrada. Esto pretende ser una forma rápida y eficiente de recuperar un listado de archivos que tienen contenidos coincidentes. -
LiteralPath– Esto le dice aSelect-Stringque utilice los valores de entrada, en lugar de interpretar valores como*como un comodín. Si la ruta incluye caracteres de escape, enciérrelos entre comillas simples para no hacer ninguna interpretación. -
NoEmphasis– En lugar de resaltar la cadena con la que coincide el patrón, desactive el resaltado de las coincidencias. Por defecto, el énfasis utiliza colores negativos basados en los colores del texto de fondo. -
NotMatch– Buscar texto que no coincida con el patrón especificado. -
Path– Especificar la ruta de los archivos a buscar. Se permiten comodines, pero no se puede especificar sólo un directorio. El valor predeterminado es el directorio local. -
Pattern– El patrón para buscar el contenido o los archivos de entrada basado en RegEx. -
SimpleMatch– Utilice una coincidencia simple en lugar de expresiones regulares. Dado que no se utiliza RegEx, el objetoMatchInfodevuelto no tiene ningún valor en la propiedadMatches. -
Raw– Imprimir las cadenas coincidentes, sin un objetoMatchInfo. Este es el comportamiento más similar agrepy no a la naturaleza más orientada a objetos de PowerShell. -
Quiet– Sólo devuelve un$trueo$falsesi se encuentra el patrón.
Usando PowerShell Grep err… Select-String
Por supuesto, saber cómo funcionan los parámetros y opciones de un cmdlet no es exactamente lo mismo que usarlo en un entorno de producción. Vamos a sumergirnos en los ejemplos y ver cómo podemos aprovechar Select-String para facilitar la búsqueda de coincidencias de texto.
Hay tres formas en las que podemos utilizar Select-String para encontrar coincidencias.
- Entre el texto entrecomillado al cmdlet
Select-String, es decir, introducir el texto. - Utilizando el texto almacenado en una variable, pasar la variable al parámetro
InputObject. - Utilizar el parámetro
Pathpara especificar los archivos donde buscar el texto.
Los archivos que estamos utilizando para probar esto son contenidos generados aleatoriamente, pero del mismo tipo que suelen encontrarse en los sistemas de producción.
Comparación simple en archivos
Comenzando con un ejemplo muy simple, busquemos Joe en un puñado de archivos CSV.
Select-String -Path "Users\*.csv" -Pattern "Joe"

Como puedes ver, esto es bastante simple, vemos como Joe está resaltado en la línea con el resto de los datos. Pero, ¿qué datos se devuelven realmente aquí? Veamos todas las propiedades de una coincidencia devuelta.
Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object * -First 1

Tenemos un par de propiedades aquí que son útiles. En particular el linepathpattern, y matches. La mayor parte de lo que queremos saber está en la propiedad matches.
Select-String -Path "Users\*.csv" -Pattern "Joe" | Select-Object -ExpandProperty Matches -First 1

Aquí puedes ver como aunque hemos utilizado una expresión simple, esta sigue siendo una expresión RegEx y los detalles posteriores disponibles.
¿Y si buscamos varios valores diferentes utilizando patrones separados por comas? Esto es útil ya que esto realmente define tres patrones diferentes y no un valor RegEx complejo.
Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry"

Puedes ver cómo es el caso, si seleccionamos sólo el filenamepattern, y line de nuestra búsqueda.
Select-String -Path "Users\*.csv" -Pattern "Joe","Marti","Jerry" | Select-Object FileName, Pattern, Line

Comparaciones RegEx más complejas
Ahora que hemos demostrado algunos de los métodos de coincidencia más simples, ¿qué tal si utilizamos RegEx más para buscar patrones más útiles? Los tres ejemplos aquí buscan direcciones de correo electrónico, direcciones IP y números de la seguridad social (SSN). Los patrones utilizados aquí no son la única manera de construir una búsqueda RegEx, y puede haber maneras más fáciles. PowerShell Grep (Select-String) es un cmdlet bastante avanzado.
Veamos si los correos electrónicos están contenidos en nuestros archivos. El uso de una coincidencia RegEx algo compleja, como se muestra a continuación, demostrará la búsqueda de esas coincidencias.
Select-String -Path "Users\*.csv" -Pattern '\\b+\.{2,4}\b' | Select-Object -First 10

Por supuesto, lo más preocupante podría ser si hubiera SSNs incluidos en un archivo. Una coincidencia muy simple para esto sería la siguiente.
Select-String -Path "Users\*.csv" -Pattern '\d\d\d-\d\d-\d\d\d\d' | Select-Object -First 10

Finalmente, ¿qué pasa si queremos buscar algunas direcciones IP en nuestro archivo? Usando otra expresión RegEx para buscar ese patrón, hace un trabajo rápido.
Select-String -Path "Users\*.csv" -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' | Select-Object -First 10

Una advertencia sobre este RegEx. Técnicamente, esto coincidirá con valores hasta 999.999.999.999 que es una IP no válida. Puedes construir expresiones RegEx más precisas que serán más largas, pero es una compensación dependiendo de lo que estés buscando hacer.
Búsqueda con Contexto
El contexto es muy útil en la resolución de problemas, ayuda a explicar lo que está sucediendo antes de que ocurra un evento y después. Por ejemplo, busquemos en un log de Apache y encontremos este suspendedpage.cgi texto.
Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -First 1

El > simple indica la línea coincidente, y hay una línea antes de la coincidencia y después de la coincidencia. En este ejemplo, esto podría indicarnos que el bot de Google estaba buscando robots.txt y, lamentablemente, recibió un resultado suspendedpage.cgi en su lugar. A continuación, fue a probar la página de inicio y quizás obtuvo el mismo error.
¿Qué contiene exactamente la propiedad context tal y como la emite el objeto MatchInfo? Si ampliamos esa propiedad, puedes ver que hay PreContent y PostContent. Esto significa que puedes manipular esto más adelante si es necesario.
Select-String -Path "Web\*.txt" -Pattern "suspendedpage.cgi" -Context 1 | Select-Object -ExpandProperty Context -First 1 | Format-List

Otros ejemplos de búsqueda a través de archivos de registro se encuentran en artículos como Making Sense of the Microsoft DNS Debug Log que demuestra el uso de Select-String para mirar a través de un registro de depuración de DNS. El grep de PowerShell es fuerte en ese post.
Conclusión
Grep es una herramienta increíblemente útil en el mundo Linux, y Select-String ofrece gran parte de la misma funcionalidad en el mundo PowerShell. La adición de la naturaleza orientada a objetos de PowerShell sólo sirve para mejorar la utilidad y la utilidad que el cmdlet ofrece.
Para muchos administradores de sistemas, ser capaz de buscar rápida y eficientemente los archivos de registro sobre diversos tipos, junto con la comprensión del contexto, es una habilidad increíblemente importante y necesaria. PowerShell Select-String hace que esto sea fácil de hacer y ahorra innumerables horas de solución de problemas!