Comando Powershell en un archivo por lotes: ¿Eliminar todas las líneas del archivo de texto excepto las líneas con "foo" y "bar"?

Comando Powershell en un archivo por lotes: ¿Eliminar todas las líneas del archivo de texto excepto las líneas con "foo" y "bar"?

Tengo un archivo de texto con estas 3 líneas:

This line contains foo.
This line contains bar.
This line has neither.

Puedo ejecutar el siguiente comando en un archivo ".bat" (junto al archivo ".txt" anterior) y elimina todas las líneas del archivo de texto excepto las líneas que contienen "foo":

Powershell.exe -Command "gci *.txt | foreach { (cat $_.FullName | ? { $_ -like '*foo*' }) | set-content $_.FullName}"

Ejecutar eso tiene el efecto deseado, dejando solo esta línea en el archivo de texto:

This line contains foo.

Ahora el problema: ¿Qué pasa si quiero conservar las líneas que tienen "foo"?y"barra" en la línea?

Debo haber probado probablemente 40 o 50 combinaciones diferentes hasta ahora, poniendo un carácter de barra vertical: *foo*|*bar*, quitando los asteriscos foo|bar, poniendo asteriscos solo al principio y al final: *foo|bar*, usando una coma, sin usar una coma, usando un punto y coma, sin usar punto y coma, duplicando el -likecomando con y sin $_ y muchas otras formas.

Nada funciona: en cada intento hasta ahora, termino con el archivo de texto con el mismo aspecto, con las tres líneas originales que contienen foo (línea 1), bar (línea 2) y ninguna de las dos (línea 3).

Para asegurarme de no estar editando el comando y cometiendo un error, periódicamente elimino mis ediciones y ejecuto el comando nuevamente para simplemente eliminar líneas sin "foo" en la línea y funciona, o simplemente pego el comando nuevamente. pruébelo nuevamente, luego comience a intentar editarlo para incluir "barra", sin éxito.

Ya hice esta pregunta recientemente, pero supongo que la redacción del título no quedó clara. Alguien ha intentado responder, pero todas las respuestas que han proporcionado no han funcionado, al menos cuando coloco el comando en un archivo por lotes y lo ejecuto junto al archivo de texto, tal vez les esté funcionando, usando un método diferente para el que soy, no lo sé.

¡Tenga en cuenta que estoy usando un comando de PowerShell en un archivo por lotes!No estoy escribiendo en una consola ni usando scripts de ps1. No necesito hacer nada de eso, porque el primer comando que mencioné anteriormentefuncionapara eliminar todas las líneas con "foo".

Obviamente, dado que eso funciona, el comando se puede usar como base para agregarlo, de modo que pueda manejar "foo" y "bar" en un solo comando.

A menos, por supuesto, que esto sea 100% imposible, lo cual después de aproximadamente 4 días de probar 40 o 50 variaciones diferentes del comando, ¡es lo que estoy empezando a sospechar!

Por favor, si alguien responde a esto, publique un comando de archivo por lotes como el que tengo arriba. Por favor, no me diga que cambie al uso de scripts de ps1 ni me dé respuestas que expliquen qué escribir en una ventana de la consola.

El comando que publiqué arriba simplemente necesita algún tipo de enmienda para que se pueda agregar "bar" a "foo", de modo que maneje más de una cadena de texto.

La razón por la que esto es tan difícil parece ser que si ejecuta un comando para eliminar todas las líneas excepto las que tienen "foo", entonces ya habrá eliminado las líneas con "bar". Sospecho que esta es la razón por la que a nadie se le ha ocurrido una solución que funcione todavía y tal vez simplemente no la haya.

Gracias de antemano a cualquiera que tenga una respuesta funcional. Normalmente estas cosas se responden aquí muy rápido, o simplemente sigo probando diferentes maneras y consigo que funcione, pero esta vez no, es realmente difícil por alguna razón.

Respuesta1

Simplemente use dos condiciones separadas unidas con OR:

cat $_.FullName | ? { $_ -like '*foo*' -or $_ -like '*bar*' }

Se pueden usar paréntesis para agregar claridad, pero son opcionales:

{ ($_ -like '*foo*') -or ($_ -like '*bar*') }

publique un comando de archivo por lotes como el que tengo arriba. Por favor, no me diga que cambie al uso de scripts de ps1 ni me dé respuestas que expliquen qué escribir en una ventana de la consola.

Son literalmente lo mismo. No importa cómo invoque una secuencia de comandos de PowerShell: ya sea que esté almacenada en un archivo, pasada a través de la línea de comandos o ingresada por el teclado, sigue siendo una secuencia de comandos de PowerShell y sigue las mismas reglas de sintaxis.

Respuesta2

Puedes usar select-stringen su lugar que toma expresiones regulares:

gci *.txt | % { (cat $_.FullName | select-string -pattern 'foo|bar') | set-content $_.FullName -Force }

select-stringle permite realizar coincidencias de expresiones regulares más complicadas en el futuro si es necesario.


Otras lecturas

información relacionada