Ejecute un bloque condicionalmente en la salida grep

0

He encontrado varias soluciones a este problema, pero desafortunadamente ninguna de ellas parece funcionar en mi ventana de Windows.

Estoy ejecutando un FORbucle en un archivo por lotes para recorrer varios archivos de texto. Para cada archivo de texto, quiero ECHOsu nombre (y posiblemente redirigir la salida al archivo) si un grep(de WinGNU) devuelve una línea. Una búsqueda rápida en Google me muestra que lo haga de esta manera:

IF grep -c pattern file ( stuff )

Sin embargo, esto arroja un error

-c was unexpected at this time.

Alternativamente, pensé que podría usar el código de salida de esta grep --quietmanera:

grep -q pattern file
IF ERRORLEVEL 1 ( stuff )

Esto siempre falla la prueba IF, incluso cuando el grep tiene éxito.

¿Hay una buena manera de ejecutar una declaración condicional en Windows si mi grep encuentra una coincidencia?

Mi código es:

SET locations=( a, long, list, of, last, two, octets )
SETLOCAL ENABLEDELAYEDEXPANSION

FOR %%r IN %locations% DO (
    grep -i "^\[CardSwipe\]" \\10.0.%%r\path\to\file.ini
    IF ERRORLEVEL 1 echo %%r

Mi salida es:

[this line left intentionally blank] :)
Adam Smith
fuente
¿Qué versión de Windows? Si es Vista o posterior, PowerShell probablemente sea más adecuado.
Iszi
@Iszi win7, pero preferiría lotes a PowerShell ya que tendría que aprender el último. Dicho esto: este puede ser mi último impulso para aprender PowerShell :)
Adam Smith
Y debería estar aprendiendo RegEx. ¿Podrías analizar eso greppor mí? En particular, ¿qué tipo de cadenas estás tratando de combinar?
Iszi
@Iszi una línea que comienza con una [CardSwipe]mayúscula y minúscula literal . Estoy escaneando un conjunto de iniarchivos que deberían haber [CardSwipe]comentado, así que necesito saber si alguno de ellos todavía comienza [CardSwipe](en lugar de estar oculto detrás del rem, por ejemplo;[CardSwipe]
Adam Smith
Okay. Creo que tengo una solución de PowerShell para ti.
Iszi

Respuestas:

1

No puedo pensar en una buena manera de hacer esto con Batch, especialmente porque traes herramientas de línea de comandos no nativas con las que no estoy familiarizado. Sin embargo, PowerShell generalmente es mucho más adecuado para tareas como esta.

Esto debería hacer el trabajo por usted en PowerShell:

$Hosts = @('1.1','1.2','101.243','54.28')
$Hosts | ForEach-Object {
    if ((Get-Content "\\10.0.$_\path\to\file.ini" | Select-String "^\[CardSwipe\]").length -ne 0) {
        Write-Output $_}}

Aquí está el desglose:

  1. Lo definimos $Hostscomo una matriz que contiene cadenas que representan los dos últimos octetos de cada sistema a verificar. Un método alternativo para configurar esto sería tener un archivo de texto con una entrada por línea.
  2. Luego canalizamos la matriz en la ForEach-Objectcual, como su nombre lo indica, ejecutará comandos para cada objeto en la matriz. Si utiliza un archivo de texto como lista, deberá buscarlo Get-Contenty luego canalizarlo ForEach-Objecten lugar de la variable.
  3. El guión en la ifcondición es lo que va a cazar por ti.
  4. Get-Content hace lo que dice en la lata: obtiene el contenido de las cosas.
  5. "\\10.0.$_\path\to\file.ini"es el objetivo que estamos dando Get-Content. Al envolver la cadena entre comillas dobles, le estamos diciendo a PowerShell que queremos que expanda las variables dentro de la cadena antes de pasar el parámetro. $_es una variable incorporada que hace referencia al objeto actual en el que trabajan cosas como ForEach-Object.
  6. La salida de Get-Contentse canaliza a Select-String. Select-Stringes más o menos grep para PowerShell; de hecho, estoy un poco sorprendido de que no haya un alias incorporado para este ya que otros cmdlets (lo que llaman comandos de PowerShell) tienen alias a comandos * nix similares como ls y wget .
  7. "^\[CardSwipe\]"- Oh si. Select-Stringtoma RegEx por cierto.
  8. Los comandos de ajuste entre paréntesis le permiten recuperar directamente las propiedades de los objetos que generan, sin tener que volcarlos primero en variables u otra cosa. Entonces, ( ... ).lengthsignifica que quiero obtener la longitud de cualquier objeto que salga del script dentro del paréntesis. Para cadenas, esta es la longitud básica de los caracteres. Para las matrices, este es el número de miembros en la matriz. Cuando se recupera un archivo de texto u objeto similar, se devuelve como una "matriz de cadenas". Entonces, el valor de la propiedad de longitud del objeto será igual al número de líneas en el texto.
  9. -nees el operador de comparación para "no es igual a". Si Select-Stringno encuentra coincidencias, su salida será una matriz nula con longitud cero. Cualquier otra cosa tendrá una longitud de 1 o más, por lo que activamos el ifencendido -ne 0.
  10. Write-Outputes otro de esos comandos autoexplicativos. Escribe salida. En este caso, le estamos diciendo que queremos generar el objeto actual que está procesando ForEach-Object. Por supuesto, dado que esto está dentro del ifbloque, solo sucederá cuando el archivo ini coincida con las condiciones dadas. La salida será cualquiera de los "últimos dos octetos" que se procesaron cuando eso sucedió.
Iszi
fuente
Genial, gracias. Tendré que analizar un poco la manipulación de cadenas en powershell. En el lote que estaba haciendoset current=%%r; set deviceinfo=site: %current:~-5,-4% device: %current:~-1%
Adam Smith
Por desgracia, todavía estaba esperando una respuesta por lotes en lugar de PowerShell. Sin embargo, agradezco su trabajo y gracias por escribir la explicación detallada. Como voy a tener que implementar esto en Powershell, ¡tengo que hacer algunos deberes y su explicación detallada solo puede ayudar con eso! Gracias de nuevo.
Adam Smith
@ AdamSmith Podría ayudar a completar las piezas que faltan, pero no estoy exactamente seguro de qué hace ese bit en su comentario. Si hay algo más con lo que necesita ayuda, siempre puede buscar aquí o hacer una pregunta de PowerShell .
Iszi