el signo =

Iniciado por Orni1, 16 Septiembre 2017, 13:49 PM

0 Miembros y 1 Visitante están viendo este tema.

Eleкtro

#10
Cita de: Orni1 en 27 Septiembre 2017, 23:03 PMEntiendo que es un código obsoleto y que hay otras opciones mas actuales y mejores

Bueno, "obsoleto" es un término muy...peliagudo y más de una vez me han criticado por llamar obsoleto a las cosas, así que dejémoslo en "insuficiente". Simplemente Batch no da la talla necesaria para cubrir ciertas necesidades de forma eficiente...




Cita de: Orni1 en 27 Septiembre 2017, 23:03 PMMi desconocimiento es tal que todavía no soy capaz de saber como es posible que el código del compañero funcione

Sinceramente no me entusiasma ponerme a analizar y desglosar códigos espagueti y menos escritos en Batch, pero lo haré para intentar ayudarte a que trates de discernir por ti mismo la gravedad del asunto:

Empecemos por la parte más relevante del código, estas lineas:

Citar@echo off
set n=HT
setlocal enabledelayedexpansion
for /f "tokens=* delims=" %%x in ('type texto.txt') do (
set linea=%%x
set linea=!linea:version=%n%!

En esta variable se define el reemplazamiento ("HT")
Citar
Código (dos) [Seleccionar]
set n=HT

Luego, lo que se hace es utilizar un búcle de tipo For /Files para iterar las lineas del texto. Cada linea de texto se almacena en la variable de For %%x:
Citar
Código (dos) [Seleccionar]
for /f "tokens=* delims=" %%x in ('type texto.txt') do (...

Cada linea se reasigna en la variable !linea!
Citar
Código (dos) [Seleccionar]
set linea=%%x
...es decir, aquí tanto el valor de la variable de For %%x como de la variable "linea" es: "version=85045"

Seguidamente se lleva a cabo un string replacement (el reemplazamiento de texto) en el que se le indica que se debe reemplazar el texto "versión" (recuerda que esto se hace en todas las lineas) por el valor de la variable %n%, es decir, "HT":
Citar
Código (dos) [Seleccionar]
set linea=!linea:version=%n%!
...y es aquí donde la linea de texto pasa a ser de "version=85045" a "HT=85045".

Ese reemplazamiento de por si ya es un fallo muy grave, puesto que dará falso positivo / resultados indeseados en cualquier linea que contenga el texto "version". Por ponerte un ejemplo, esto:
texto_Version_texto=85045
Será convertido a esto otro:
texto_HT_texto85045

Bueno, sigamos...

El caracter del símbolo igual = se define más tarde en esta variable:
Citar
Código (dos) [Seleccionar]
Set Caracter=^=
...esto de por si es una práctica no recomendable en Batch que pone en peligro posibles fallos de sintaxis en futuras evaluaciones, puesto que la variable no está encerrada entre comillas dobles. Debería haber sido declarada de la siguiente manera:
Set "Caracter=="
...no es necesario escapar el caracter.

Luego, en la rutina :Buscador se itera cada caracter de la linea, es decir, se va procesando cada caracter hasta encontrar el caracter que coincida con la variable "%caracter%", es decir, el símbolo de igual =.
De nuevo aquí se usa una mala práctica además de ser muy peligrosa (y de verdad), la Recursividad, esto es cuando una función se llama así misma de forma indefinida para resolver un problema ( en el código: Goto Buscador ). Esto quiere decir que si usases ese algoritmo recursivo (la rutina :Buscador del script de @Aincrad) sobre un archivo con muchas (pero muchas) lineas de texto/caracteres, inevitablemente desembocaría en un error conocido como Stack Overflow, el cual indica un agotamiento de espacio en la capacidad de almacenamiento de la pila de llamadas por un exceso de llamadas (como resulta evidente), y este error imposibilitaría que el programa/algoritmo pudiese proseguir y finalizar su ejecución.

..Por no decir que para cumplir el objetivo de reemplazar un texto se han tenido que escribir ni más ni menos que 104 lineas de código en Batch, compañero, 104. Fíjate en las 10 simples lineas que te ofrece el lenguaje PowerShell para llevar a cabo la misma tarea y de forma mucho más estable. Ojo, no estoy insinuando que esto tenga que ver con la forma de programar y estructurar/organizar del compañero @Aincrad (bueno, un poco si xD, el código se puede simplificar mucho) sino con las limitaciones por naturaleza que implica el uso de Batch, donde en otros lenguajes son 10 lineas, en Batch serán 100... e imperfectas.

Eso son solo algunos de las muchos problemas que uno tiene que sufrir al trabajar con Batch, es horrible e inestable realizar este tipo de tareas en Batch, por que Batch no fue diseñado para esto, pero la gente se acostumbra y se acostumbra y se creen que les vale para todo... todo lo quieren hacer con Batch, incluso, cuando NO SE PUEDE (o se puede, pero MAL... de forma inestable).




Mira, para que puedas tener una alternativa a la solución de @Aincrad, te voy a enseñar un código que desarrollé hace mucho tiempo y quizás podría servirte para llevar a cabo modificaciones de archivos de texto en Batch como reemplazar texto de forma sencilla:


El código entero lo copiarias dentro de tu script, abajo del todo, tal que así:
Código (dos) [Seleccionar]
@Echo OFF
REM Aquí los comandos originales de tu script...
Echo Hello World !!
REM ...
Exit

REM Aquí abajo insertas todo el código de la rutina :TEXTMAN
:TEXTMAN
REM ...


y la sintaxis de utilización sería la siguiente:
Call :TEXTMAN RSA "Archivo.txt" "Perl=" "HC"

...pero hace años que no utilizo ese código del demonio, no sé si estará del todo libre de bugs, y no lo pienso revisar (siendo un código escrito en el odioso Batch xD).




Cita de: Orni1 en 27 Septiembre 2017, 23:03 PMsi tengo que ir a algún sitio y me das la opción de conducir en mi coche viejo o en el deportivo mas potente y mas moderno elegiré el coche viejo que aunque no soy piloto se como conducirlo mas o menos.

Es una decisión tan respetable como cualquier otra, pero piensa que el "coche" antiguo siempre manifestará algún tipo de problemas: se atascarán las marchas, el cuentakilómetros irá mal, el retrovisor no encajará bien, tendrás que darle golpecitos a la puerta para que se cierre del todo, te sentirás escaso de accesorios útiles en su interior... etcétera. El "coche" antiguo te podrá hacer sentir muy cómodo por esa sensación de familiaridad, pero eso no quita la realidad, y la realidad es que es inevitable que lo antiguo se desgaste y se invente algo que lo supere con creces, algo actual, más completo y sofisticado mientras que lo antiguo se desgasta, y ese desgaste (u obsolescencia) solo conseguirá que tus movimientos sean excesivamente torpes en comparación con lo que actualmente tienes a tu disposición (lo "moderno")...

De todas formas, si migrases a PowerShell no sería lo equivalente a comprarse el mejor coche deportivo del mundo, sino más bien sería como comprarse un coche mucho mejor que el coche antiguo para estos tiempos que corren, y sin perder esa relación de...manejo o aprendizaje amistoso.

Una de las muchas ventajas que supondría aprender otro lenguaje de programación... y ya no me estoy refiriendo a PowerShell, sino AL QUE SEA, seria darte cuenta de como lo que para desarrollar un algoritmo en Batch puede suponer escribir 100 lineas (que además serían 100 lineas de código espagueti e inestable), en ese otro lenguaje podrías simplificarlo a 10 lineas... con la diferencia y el ahorro de tiempo que eso conlleva, entre otras cosas.
Luego hay otros beneficios como las características de depuración de código o el soporte de un paradigma orientado a objetos, son cosas que no serían tan perceptibles para una persona que se acabe de iniciar en la programación o que no sepa mucho, pero siguen siendo cosas que en Batch tampoco tienes y te están limitando...sin que sepas demasiado bien el por qué.

No intento convencerte de nada xD pero quería darte mi opinión al respecto para que lo pudieras reflexionar desde la perspectiva adecuada (no sé si lo habré conseguido). Si yo quisiera recomendarte lo que considero el "mejor" lenguaje entonces no sería PowerShell (sería VB.NET o C#), PowerShell es el lenguaje que te recomiendo si quieres un lenguaje de scripting que no necesite instalar ningún "intérprete" adicional en Windows y con el que poder programar scripts sencillos o avanzados, me refiero, poder hacer de todo con libertad, estabilidad y sofisticación (sin duda infinitamente más que en Batch y VBS... en todos los sentidos posibles).

También debo decir que por supuesto para escribir scripts de forma esporádica para resolver algún problemilla como éste de reemplazar lineas de texto pues... no necesitas realizar el tremendo esfuerzo de aprender un nuevo lenguaje, pero si en el futuro sigues necesitando realizar tareas como esta entonces te convendría aprender, sino PowerShell entonces como mínimo Visual Basic Script (el cual sería un lenguaje más capacitado que Batch, pero menos que PowerShell), y esos meses que has pasado "atascado" en Batch probablemente habrían sido unas pocas horas o unos cuantos dias en uno de esos lenguajes...




Cita de: Orni1 en 27 Septiembre 2017, 23:03 PMque me indiques como hago uso de lo que propones, quiero decir... copio el código lo pego en un archivo de texto y que extensión debo ponerle.

Si te fijas bien en mi comentario, justo arriba del bloque de código escribí "script.ps1", pues bien, ese "ps1" hace referencia a la extensión del archivo. Si, simplemente copia y pega el código en un archivo de texto y lo guardas con extensión "ps1".

En esta linea especificarías la ruta del archivo de origen (el archivo que contiene el texto "Perl="):
Citar
Código (ini) [Seleccionar]
$srcFilePath  = ".\Iput Text.txt"

En esta linea especificarías la ruta del archivo de destino, es decir, el archivo donde se van a escribir el texto con los cambios/reemplazamientos hechos:
Citar
Código (ini) [Seleccionar]
$dstFilePath  = ".\Output Text.txt"

Esta linea no creo que necesites modificarla, y además creo que habla por si sola... el primer argumento de la función "Replace" es el texto a reemplazar ("Perl="), y el segundo argumento es el texto por el cual será reemplazado ("HT"):
Citar
Código (ini) [Seleccionar]
$replacedText = ($filecontent).Replace("Perl=", "HT")

¿Cómo utilizar el archivo/script?, pues sencillamente haciendo click derehcho sobre el archivo -> Ejecutar con PowerShell. O bien puedes abrir una instancia de la consola de Windows (CMD.exe) para iniciar la consola de Powershell tal que así:

Código (dos) [Seleccionar]
@Echo OFF
PowerShell.exe "C:\Ruta absoluta del script.ps1"





Cita de: Orni1 en 27 Septiembre 2017, 23:03 PMalgún enlace donde poder iniciarme en Power Shell

¿Cómo llevas el dominio del idioma Inglés?, la mayor fuente de documentación así como guías/tutoriales de introducción para iniciarse en el lenguaje y basicamente todo lo que necesitas aprender al respecto (incluyendo porsupuestísimo la referencia de los miembros del lenguaje al completo) lo puedes encontrar en la famosa web MSDN.com de Microsoft y la nueva docs.microsoft.com, eso sí, en perfecto Inglés:


Muchos artículos tanto en la MSDN como en docs.microsoft.com están en Castellano, tan solo tienes que modificar la dirección URL para reemplazar la localización del idioma "en-us" por "es-es", por ejemplo:
...pero la mayoría de artículos no están traducidos, te aviso.

Y luego en la galería de códigos de Technet puedes encontrar pues... eso, muchos scripts de programadores profesionales de PowerShell que puedes descargar para aprender analizando el código fuente:

( la gran mayoría de scripts que encontrarás ahí están enfocados a la administración web puesto que el propósito de utilización principal del lenguaje Powershell es la administración de servidores web, por otro lado Batch / CMD es un simple instrumento desarrollado con el único propósito de cubrir una interoperabilidad muy básica por no decir cutre, pobre e INUTIL entre el usuario y la shell de Windows, ofreciendo así la posibilidad de poder llevar a cabo tareas básicas (insisto en lo de BÄSICAS, muy, muy básicas, por que es así, Batch no da para más) de administración del sistema operativo y sistema de archivos en general; eso no quita que puedas y debas usar Powershell como reemplazamiento del antiguo Batch y cubrir todas esas cosas que en Batch resultarían muy tediosas o engorrosas de llevar a cabo. )

Bueno, creo que para variar he escrito un monólogo demasiado extenso... lo siento, pero no me gusta dejarme ningún detalle importante sin su debida aclaración.

Un saludo.








**Aincrad**

 :o . Elektro le escribiste un testamento .. ..  :o  :laugh:  ;D




Orni1

Madre mía, ya hay donde leer muchísimas gracias primero por tu extensión en el análisis, segundo por tus sabios consejos y tercero por la voluntad de ayuda y tu tiempo.

Comentar que el texto a tratar siempre va ser de 5 ó 6 lineas por lo que se acota bastante el posible error no obstante probaré a modificar el código para incluir el tuyo nuevo como indicas y para aprender alguna cosa mas.

Gracias a los dos, Elektro y **Aincrad**.  ;-)

Orni1

#13
Estoy tratando de usar el ps1 de Elektro para mi código.
El primer problema que he tropezado es con los permisos de ejecución de script power shell en el pc ya que la llamada

   @Echo OFF
   PowerShell.exe "C:\Ruta absoluta del script.ps1"


No funciona.

Investigando el tema he llegado a la conclusión que es problema de permisos ya que cada vez que ejecuto el ps1 --> botón derecho ejecutar con PS la consola pide permiso para la ejecutar ese script.

He descubierto que la llamada desde cmd se puede hacer así (igual le sirve a alguien):

@Echo OFF
PowerShell.exe -ExecutionPolicy Bypass -Command "& Ruta absoluta del script" >nul


Hasta ahí he llegado bien, ahora el problema que me surge y no soy capaz de encontrar solución, es
la gestión de la ruta. El script rula bien si pongo todos los archivos en el mismo directorio pero mi código.bat estaba dirigido a la ruta %temp%\ttdje la ruta con la variable %temp% la tengo clara en cmd pero pero como se escribe la ruta   %temp%\ttdje en power shell, porque poniendo la ruta absoluta va bien, pero me gustaría poner la variable de la carpeta temp pero no se como se redacta en Power Shell y esto ya se que no rula:

@Echo OFF
PowerShell.exe -ExecutionPolicy Bypass -Command "& %temp%\ttdje\script.ps1" >nul


Imagino que el problema es que las variables de ruta no se escriben igual y en esa llamada, pese a ser desde cmd la variable de temp deberá ir escrita para PowerShel.


Eleкtro

#14
Cita de: Orni1 en  1 Octubre 2017, 14:37 PM
@Echo OFF
PowerShell.exe -ExecutionPolicy Bypass -Command "& %temp%\ttdje\script.ps1" >nul

La llamada con la sintaxis que estás utilizando funciona correctamente, no sé exactamente que supuesto error dices estar teniendo... podrías intentar explicarlo de otro modo. De todas formas en caso de error PowerShell te mostrará información respecto a ese error... muestranos la información de ese error.

Supongo que esto no será lo que te ocurre, pero por si acaso: si el problema es que en tu equipo has modificado el valor de la variable de entorno TEMP y ésta apunta a una ruta con espacios en blanco, o si en realidad la carpeta "ttdje" o el archivo "script.ps1" no se llama así y es un nombre con espacios en blanco entonces tienes que encerrar la ruta entre comillas dobles...y esas comillas dobles debes escaparlas en el argumento. Ejemplo:

PowerShell.exe "& \"%TEMP%\ttdje\script.ps1\" "

Saludos.








Orni1

Lo he dicho mal porque ni yo misma lo entendía

Tengo el bat ejecutando en "E:\PS\prueba_descomprime", con la llamada mencionada que si que rula.

Pero lo que no se es escribir la variable en el script.ps1 el script está así:


    [System.Reflection.Assembly]::LoadWithPartialName("System.Text.dll")
     
    $srcFilePath  = ".\temp.txt"
    $dstFilePath  = ".\temp2.txt"
    $textEncoding = [System.Text.Encoding]::Default
     
    $filecontent  = [System.IO.File]::ReadAllText($srcFilePath, $textEncoding) 

    $replacedText = ($filecontent).Replace(".zip", "")

    [System.IO.File]::WriteAllText($dstFilePath, $replacedText, $textEncoding)
     
    Write-Host $replacedText

    Exit(0)


Ejecutado el script con el botón derecho funciona bien porque lo ejecuto en la carpeta temporal: "C:\Users\YO\AppData\Local\Temp\ttdje"

Pero realizando la llamada desde el bat lo único que hace es crear un archivo temp2 vacío en la ubicación del bat.
Solución a esto es poner la ruta en el script y entonces si que rula.

Pero si me llevo el código a otro pc ya no rula porque la ruta que tiene temp es diferente, la solución es poner la ruta %Temp% en el script.ps1 en forma de variable en vez de ruta absoluta eso es lo que no se como hacer cuál es la redacción de la ruta "%TEMP%\ttdje\temp.txt" en Power Shell









Eleкtro

#16
Cita de: Orni1 en  1 Octubre 2017, 21:09 PM
la solución es poner la ruta %Temp% en el script.ps1 en forma de variable en vez de ruta absoluta eso es lo que no se como hacer cuál es la redacción de la ruta "%TEMP%\ttdje\temp.txt" en Power Shell

Cita de: Orni1 en  1 Octubre 2017, 21:09 PMEjecutado el script con el botón derecho funciona bien porque lo ejecuto en la carpeta temporal: "C:\Users\YO\AppData\Local\Temp\ttdje"

Pero realizando la llamada desde el bat lo único que hace es crear un archivo temp2 vacío en la ubicación del bat.

Ah, bueno, ahora entiendo lo que dices. Lo que te sucede es que no has modificado el directorio de trabajo del executable PowerShell.exe antes de iniciarlo. Por defecto, el directorio de trabajo será el mismo directorio de trabajo de tu batch-script, por eso el script de PowerShell te crea un archivo en el directorio donde tienes ubicado el archivo .bat.

Puedes modificar el directorio de trabajo actual antes de ejecutar PowerShell.exe desde Batch con el comando PUSHD (o en su defecto el comando CD):
Código (dos) [Seleccionar]
@Echo OFF
PUSHD "%TEMP%\ttdje"
PowerShell.exe "& \"%CD%\script.ps1\" "
POPD


O bien puedes modificarlo después en el script de PowerShell utilizando el cmdlet Set-Location:
Código (ini) [Seleccionar]
Set-Location ([System.IO.Path]::GetTempPath() + "ttdje")
Write-Host (Get-Location)

$srcFilePath  = ".\temp.txt"
$dstFilePath  = ".\temp2.txt"
# etc ...


PD: O también podrías hacer que el script recoja los argumentos command-line para indicarle una ruta específica y que la asigne como directorio de trabajo, pero con las dos soluciones de arriba es más que suficiente.

Saludos.








Orni1

Esta llamada funciona bien con el script como estaba y tambien modificandolo como me dices:

    @Echo OFF
    PUSHD "%TEMP%\ttdje"
    PowerShell.exe "& \"%CD%\script.ps1\" "
    POPD




Modificando el script y con la llamada vieja en el bat que teníamos, no rula:

    Set-Location ([System.IO.Path]::GetTempPath() + "ttdje")
    Write-Host (Get-Location)

    $srcFilePath  = ".\temp.txt"
    $dstFilePath  = ".\temp2.txt"
    [System.Reflection.Assembly]::LoadWithPartialName("System.Text.dll")

    $textEncoding = [System.Text.Encoding]::Default
     
    $filecontent  = [System.IO.File]::ReadAllText($srcFilePath, $textEncoding) 

    $replacedText = ($filecontent).Replace(".zip", "")

    [System.IO.File]::WriteAllText($dstFilePath, $replacedText, $textEncoding)
     
    Write-Host $replacedText

    Exit(0)


... así tampoco

    Set-Location ([System.IO.Path]::GetTempPath() + "ttdje")
    Write-Host (Get-Location)

    $srcFilePath  = ".\temp.txt"
    $dstFilePath  = ".\temp2.txt"

    $textEncoding = [System.Text.Encoding]::Default
     
    $filecontent  = [System.IO.File]::ReadAllText($srcFilePath, $textEncoding) 

    $replacedText = ($filecontent).Replace(".zip", "")

    [System.IO.File]::WriteAllText($dstFilePath, $replacedText, $textEncoding)
     
    Write-Host $replacedText

    Exit(0)


Dejo el bat con esta llamada:

Código (dos) [Seleccionar]
    @Echo OFF
    PUSHD "%TEMP%\ttdje"
    PowerShell.exe "& \"%CD%\script.ps1\" "
    POPD


y el script así:

Código (perl) [Seleccionar]
    Set-Location ([System.IO.Path]::GetTempPath() + "ttdje")
    Write-Host (Get-Location)

    $srcFilePath  = ".\temp.txt"
    $dstFilePath  = ".\temp2.txt"
    [System.Reflection.Assembly]::LoadWithPartialName("System.Text.dll")

    $textEncoding = [System.Text.Encoding]::Default
     
    $filecontent  = [System.IO.File]::ReadAllText($srcFilePath, $textEncoding) 

    $replacedText = ($filecontent).Replace(".zip", "")

    [System.IO.File]::WriteAllText($dstFilePath, $replacedText, $textEncoding)
     
    Write-Host $replacedText

    Exit(0)


Así funciona.