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-String
só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 objetoMatchInfo
para 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 objetoMatchInfo
emitido para incluir una nueva propiedadContext
que contiene las líneas especificadas.
Tenga en cuenta que si canaliza la salida de
Select-String
a otra llamadaSelect-String
, el contexto no estará disponible ya que sólo se busca en la única propiedad resultanteMatchInfo
line
.
-
Culture
– Utilizado con el parámetroSimpleMatch
, especifica una cultura que debe coincidir con el patrón especificado. Esto incluye opciones comoen-US
es
, ofr-FR
como ejemplos. Otras opciones útiles son las opcionesOrdinal
yInvariant
Ordinal
es para comparaciones binarias no lingüísticas yInvariant
es 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
Encoding
también acepta IDs numéricos de páginas de código registradas como1251
o nombres de cadena comowindows-1251
. -
A partir de PowerShell Core 6.2, el parámetro
Encoding
también acepta IDs numéricos de páginas de código registradas como1251
o 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ámetroExclude
Include
incluirá 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-String
que 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 objetoMatchInfo
devuelto no tiene ningún valor en la propiedadMatches
. -
Raw
– Imprimir las cadenas coincidentes, sin un objetoMatchInfo
. Este es el comportamiento más similar agrep
y no a la naturaleza más orientada a objetos de PowerShell. -
Quiet
– Sólo devuelve un$true
o$false
si 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
Path
para 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 line
path
pattern
, 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 filename
pattern
, 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!