0

I have the following code.

@echo off

SetLocal EnableDelayedExpansion & REM All variables are set local to this run & expanded at execution time rather than at parse time (tip: echo !output!)


REM Get full path to run.bat file (excluding filename)
set wrapper_dir=%~dp1dist
set arch=amd64.exe
set system=windows

mkdir %wrapper_dir%

REM get_my_version - Find the latest version available for download.
(for /f %%i in ('curl -f -s https://prysmaticlabs.com/releases/latest') do set my_version=%%i) || (echo [31mERROR: require an internet connection.  ESC[0m && exit /b 1)
echo ESC[37mLatest release is %my_version%.ESC[0m
IF defined USE_MY_VERSION (
    echo [33mdetected variable USE_MY_VERSION=%USE_MY_VERSION%[0m
    set reason=as specified in USE_MY_VERSION
    set my_version=%USE_MY_VERSION%
) else (
    set reason=automatically selected latest available release
)
echo Using version %my_version%.

set PROGRAM_REAL=%wrapper_dir%\program-%my_version%-%system%-%arch%

if [%1]==[program-real] (
    if exist %PROGRAM_REAL% (
        echo ESC[32mBeacon chain is up to date.[0m
    ) else (
        echo ESC[35mDownloading beacon chain %my_version% to %PROGRAM_REAL% %reason%[0m
        for /f "delims=" %%i in ('curl --silent -w "%%{http_code}" -L "https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%" -o "%PROGRAM_REAL%" ') do set http=%%i
        if %http%=="400" (
            echo ESC[35mNo program real found for %my_version%ESC[0m
            exit \b 1
        )       
        curl --silent -L https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%.sha256 -o %wrapper_dir%\beacon-chain-%my_version%-%system%-%arch%.sha256
        curl --silent -L https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%.sig -o %wrapper_dir%\beacon-chain-%my_version%-%system%-%arch%.sig
    )
)

At the line of the second for loop inside the IF statement(second IF statement) it complains ( was unexpected at this time.

The way to work around it , is to "grease" the batch file by running this command (on the prompt directly)

>for /f "delims=" %i in ('curl --silent -w "%{http_code}" -L https://prysmaticlabs.com/releases/beacon-chain-%prysm_version%-%system%-%arch% -o gg.txt') do set http=%i

ONLY then does it work

>prysm1.bat program-real version
A subdirectory or file C:\Users\HP\Documents\Investments\ethbox\prysm\dist already exists.
Latest release is v1.4.2.
detected variable USE_MY_VERSION=fake
Using version fake.
Downloading beacon chain fake to C:\Users\HP\Documents\Investments\ethbox\prysm\dist\program-fake-windows-amd64.exe as specified in USE_MY_VERSION

I know it has to do with the way the variables are expanded at execution vs parse time and that maybe a bracket, _ or other special characters are causing this. But i tried a couple of things and the problem persists. (all did not work)

  • quote the entire for with double quotes "
  • use brakets around the for
  • not using the _ in my_version.

Any ideas? thanks

UPDATES after comments below

The script now does not complain after @aschipfl 's suggestions. However the last if stat is not evaluating to true. Made the for echo the result to ensure value in if stat.

for /f "delims=" %%i in ('curl --silent -o nul -w "%%{http_code}" https://prysmaticlabs.com/releases/beacon-chain-%version%-%system%-%arch% ') do set "http=%%i" && echo %%i
  • 1
    Begin to use quotes rather than brackets in your `if` statements in order to protect spaces and other special characters, like `if "%~1"=="program-real"` and `if exist "%PROGRAM_REAL%"` and `if "%http%"=="400"`, and use `exit /B 1` rather than `exit \b 1`… – aschipfl Jul 23 '21 at 12:19
  • thanks @aschipfl that is working. let me use it throughout the rest of the script. – user443729 Jul 23 '21 at 12:54
  • Well now that its not complaining, i'm noticing how the if "%http%"=="400" is not going through. even though running it manually (directly through cmd prompt ) works ! >for /f "delims=" %i in ('curl --silent -w "%{http_code}" -L https://prysmaticlabs.com/releases/beacon-chain-%prysm_version%-%system%-%arch% -o gg.txt') do set http=%i – user443729 Jul 23 '21 at 13:02
  • @aschipfl what do you think about the last if "%http%"=="400" not equating (tried both 400 and 404)? thanks – user443729 Jul 23 '21 at 13:33
  • 1
    You are inside a code block which requires Delayed Variable Expansion. Please read [Variables not behaving as expected](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected) – Squashman Jul 23 '21 at 13:56
  • i'll review. so !var! vs %var% – user443729 Jul 23 '21 at 14:00
  • But the question further begs why did you enable delayed expansion at the top of your script if didn't seem to know how to use it? The comment in your code even says to use the variables with exclamation points. – Squashman Jul 23 '21 at 14:22
  • See [Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files](https://stackoverflow.com/a/47386323/3074564) with full details how a string comparison is done by `cmd.exe`. A string left to `==` not enclosed in `"` will be never equal a string right to `==` enclosed in `"` as the double quotes are included in the string comparison. I also don't see the reason for assigning a string to an environment variable `http` and make next a string comparison. Why is the `if` condition not directly done by last `for` using `if "%%~i" == "400"` which avoids the need of delayed expansion. – Mofi Jul 23 '21 at 18:38
  • I would strongly recommend to avoid all the __IF__ (...) __ELSE__ (...) command blocks and use instead the classic __batch__ structure with __IF__ *condition* __GOTO__ *label* which would avoid many problems you have with your code. Example: Replace `if [%1]==[program-real] (` by `if /I not "%~1" == "program-real" goto :EOF` (or a different label than predefined label for end of file) and all the lines below can be unindented by one indent as now the command block is not needed anymore for these commands executed on batch file called with first argument being `program-real` and no `)` at end. – Mofi Jul 23 '21 at 18:41
  • There can be used next `if exist "%PROGRAM_REAL%" echo ESC[32mBeacon chain is up to date.[0m& goto :EOF` and the __ELSE__ command block can be once again removed and the lines be unindented by two indents. BTW: `exit \b 1` should be `exit /b 1` with a slash instead of a backslash. – Mofi Jul 23 '21 at 18:49

1 Answers1

0

Based on all the constructive feedback, here is the final working version the summary of which :

  • Replacing [] with ""( quotes) in all if statements in order to protect spaces and other special characters.
  • Using !! vs %% for http var since it is in a block with delayed expansion
  • Check if download exists (404 error) then proceed and download.
@echo off

SetLocal EnableDelayedExpansion & REM All variables are set local to this run & expanded at execution time rather than at parse time (tip: echo !output!)

.... same code as above... 

if "%1"=="program-real" (
    if exist "%PROGRAM_REAL%" (
        echo ESC[32mBeacon chain is up to date.[0m
    ) else (
        echo ESC[35mDownloading beacon chain %my_version% to %PROGRAM_REAL% %reason%[0m
        for /f "delims=" %%i in ('curl --silent -o nul -w "%%{http_code}" -L "https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%" ') do set "http=%%i" && echo %%i
        if "!http!"=="404" (
            echo ESC[35mNo program real found for %my_version%ESC[0m
            exit /b 1
        )   
        curl -L https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch% -o %PROGRAM_REAL%
        curl --silent -L https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%.sha256 -o %wrapper_dir%\beacon-chain-%my_version%-%system%-%arch%.sha256
        curl --silent -L https://prysmaticlabs.com/releases/beacon-chain-%my_version%-%system%-%arch%.sig -o %wrapper_dir%\beacon-chain-%my_version%-%system%-%arch%.sig
    )
)