Imagine que al escribir código de PowerShell necesita buscar texto dentro de una sola cadena de caracteres o un archivo de texto, ¿Qué es lo que hace?Si usa Linux con frecuencia, probablemente conoce la utilidad popular grep. La utilidad grep le permite al usuario buscar texto usando opciones diferentes, sin embargo, esta utilidad no existe en Windows. ¿Entonces, ya no hay nada que hacer? No, porque existe el comándulo Select-String.
Digamos que tiene una gran cadena de caracteres que contiene varios nombres y domicilios de empleados. Desafortunadamente, esta cadena de caracteres no está en un formato conocido, por lo que se le obliga extraer todos los nombres de los empleados por medio de un analizador de texto (text parcing). ¿Cómo lo haría? Primero, veamos el ejemplo de cadena de caracteres que usaremos.
||Adam Bertram|| 2122 Acme Ct, Atlantic City, NJ
--||Joe Jonesy||-- 555 Lone St, Las Vegas, NV
==|Suzie Shoemaker|== 6783 Main St, Los Angelas, CA
A esta cadena le he asignado la variable $employees. Para obtener solo los nombres de los empleados de esta cadena, primero intentaré simplemente obtener la sintaxis correcta en Select-String. Para hacerlo, voy a buscar estáticamente uno de los nombres de los empleados usando el parámetro Pattern.
PS> $employees | Select-String -Pattern 'Adam Bertram'
||Adam Bertram|| 2122 Acme Ct, Atlantic City, NJ
--||Joe Jonesy||-- 555 Lone St, Las Vegas, NV
==|Suzie Shoemaker|== 6783 Main St, Los Angelas, CA
Observe que Select-String nos devolvió algo, ya que encontró una coincidencia; de lo contrario, no hubiera devuelto nada. Pero devolvió toda la cadena. ¿Porque? Bueno, la razón es porque Select-String analizó toda la cadena como una sola. Primero necesitamos averiguar cómo separar cada renglón en cadenas diferentes. Ya que cada referencia de empleado está en un nuevo renglón, puedo separarlas al dividir esta cadena en el carácter de nueva línea (`n).
PS> $employees = $employees -split "`n"
PS> $employees | Select-String -Pattern 'Adam Bertram'
||Adam Bertram|| 2122 Acme Ct, Atlantic City, NJ
Note que solo está devolviéndonos un solo renglón. ¡Nos estamos acercando! Ahora, necesitamos descubrir cómo devolver todos los renglones de los empleados. Para esto, necesito descubrir un patrón familiar que cada uno muestra. Parece que el nombre de cada empleado está rodeado por el símbolo |. Podemos usar este patrón en el parámetro Pattern en Select-String. Además, dado que el nombre y apellido de cada empleado está separado por un espacio, también podemos atender este asunto.
Ahora representaré este patrón como una expresión regular que Select-String acepta con gusto en el parámetro Pattern.
PS> $employees | Select-String -Pattern '\|\w+ \w+\|'
||Adam Bertram|| 2122 Acme Ct, Atlantic City, NJ
--||Joe Jonesy||-- 555 Lone St, Las Vegas, NV
==|Suzie Shoemaker|== 6783 Main St, Los Angelas, CA
Observe que nuevamente que Select-String ha devuelto cada renglón usando la expresión regular. Luego, necesito analizar cada nombre de los empleados. En este momento, no necesito el domicilio de cada uno. Para hacer esto, haré referencia a la propiedad Match (Coincidencias) devuelta en cada objeto coincidente que devuelve Select-String.
PS> $employees | Select-String -Pattern '\|\w+ \w+\|' | foreach {$_.Matches}
Groups : {0}
Success : True
Name : 0
Captures : {0}
Index : 1
Length : 14
Value : |Adam Bertram|
Groups : {0}
Success : True
Name : 0
Captures : {0}
Index : 3
Length : 12
Value : |Joe Jonesy|
Groups : {0}
Success : True
Name : 0
Captures : {0}
Index : 2
Length : 17
Value : |Suzie Shoemaker|
¡Nos estamos acercando! Ahora veo que la propiedad Value contiene los nombres de los empleados que necesito, pero todavía tiene esos símbolos a los lados. Esto se debe a que la coincidencia de expresiones regulares era el nombre del empleado, incluyendo los símbolos. Todavía tenemos que incluir los símbolos verticales en la búsqueda, pero no queremos que los devuelva como coincidencia. ¿Cómo lo hacemos? Una forma es usar grupos de expresiones regulares. Los grupos Regex están representados por paréntesis alrededor de la coincidencia que desea como resultado. En este caso, incluiré la cadena de expresiones regulares con el nombre y apellido del empleado e intentaré de nuevo.
PS> $employees | Select-String -Pattern '\|(\w+ \w+)\|' | foreach {$_.Matches}
Groups : {0, 1}
Success : True
Name : 0
Captures : {0}
Index : 1
Length : 14
Value : |Adam Bertram|
Groups : {0, 1}
Success : True
Name : 0
Captures : {0}
Index : 3
Length : 12
Value : |Joe Jonesy|
Groups : {0, 1}
Success : True
Name : 0
Captures : {0}
Index : 2
Length : 17
Value : |Suzie Shoemaker|
Hmm... todavía muestra la propiedad Value con los caracteres verticales. Pero ahora mire la propiedad Groups. En lugar de simplemente ser un 0, ahora muestran 0,1. Esto significa que Select-String ha capturado un grupo. Para ver este grupo, agregaré la referencia en nuestro bucle foreach nuevamente. Como cada propiedad de Groups es un conjunto, puedo hacer referencia al elemento 1 al encerrarlo con corchetes y luego hacerle referencia a la propiedad Value.
PS> $employees | Select-String -Pattern '\|(\w+ \w+)\|' | foreach {$_.Matches.Groups[1].Value}
Adam Bertram
Joe Jonesy
Suzie Shoemaker
¡Ahora puede ver que he sacado cada uno de los nombres de los empleados de la cadena de caracteres! Hay mucho más que puede hacer con Select-String, así que le sugiero echar un vistazo al contenido de la ayuda: help Select-String -Detailed para un desglose completo.
Adam Bertram
Adam Bertram is a 20-year veteran of IT. He’s currently an automation engineer, blogger, independent consultant, freelance writer, author, and trainer. Adam focuses on DevOps, system management, and automation technologies as well as various cloud platforms. He is a Microsoft Cloud and Datacenter Management MVP and efficiency nerd that enjoys teaching others a better way to leverage automation.