Search code examples
powershellbatch-filegoto

Why is my GOTO statement not working (batch)


It always goes to the first lapel no matter what is the input

I saw other posts with the same issue but none of the syntax mistakes they made were present in my script.

Here is the script :

@echo off
cls

cd /d %~dp0

echo "Include files? [Y/N]"

set /p option=

if %option%=="Y" GOTO yes
if %option%=="y" GOTO yes
if %option%=="N" GOTO no
if %option%=="n" GOTO no

:yes
cls
powershell -command "iex \"tree /f\" > \"tree-filed.txt\""
GOTO end

:no
cls
powershell -command "iex \"tree\" > \"tree-folders.txt\""
GOTO end

:end
cls
echo the tree list was created.
pause

What am I missing?


Solution

  • rifteyy's solution is effective, but some background information may be helpful:

    • As Squashman notes, an if conditional either requires both sides to be either (double-)quoted or unquoted; that is, both if %option%==y ... and if "%option%"=="y" ... work:

      • The double-quoted form is more robust, as it also handles values with metacharacters such as & correctly, but the match must be exact with respect to presence or absence of spaces.

      • Conversely, only the unquoted form is forgiving of leading and trailing spaces; e.g. if %option%==y ... still works if the user entered y rather than just y.

    • You can use if's /I option to make the comparison case-insensitive, which obviates the need to check for y and Y separately, for instance. help if shows more information.

    • tree.com is a stand-alone executable that can be called from any (Windows) shell, so there is generally no good reason to call PowerShell (powershell.exe, which is expensive), given that you can invoke tree directly from your batch file - though you may need PowerShell to control the character encoding of the output files.[1]

      • As an aside: Inside PowerShell there is no need for Invoke-Expression (iex), which should generally be avoided; the best way to invoke an external executable such as tree.com fundamentally works the same as from cmd.exe (see below).

      • If you do need PowerShell, call it as follows, for instance:
        powershell -command "tree > tree-folders.txt"

    Therefore, a streamlined version of your batch file would look like this (cls commands omitted):

    @echo off
    
    cd /d "%~dp0"
    
    :prompt
    echo "Include files? [Y/N/Q]"
    
    set /p option=
    
    if /I "%option%"=="y" GOTO yes
    if /I "%option%"=="n" GOTO no
    if /I "%option%"=="q" GOTO :eof
    goto prompt
    
    :yes
    tree /f > tree-files.txt
    GOTO end
    
    :no
    tree > tree-folders.txt
    GOTO end
    
    :end
    echo the tree list was created.
    pause
    

    As Stephan points out, the standard choice.exe utility offers a simpler prompting solution:

    choice /c ynq /m "Include files?"
    if %ERRORLEVEL% EQU 1 goto yes
    if %ERRORLEVEL% EQU 2 goto no
    goto :eof
    

    choice.exe:

    • is case-insensitive by default (use /CS for case-sensitivity)

    • accepts only a single input character from the user, which instantly exits the prompt (no Enter keypress required), with the %ERRORLEVEL% variable set to the 1-based position of the character in the list of permitted characters passed to /C

      • Note: The above deliberately uses, e.g., if %ERRORLEVEL% EQU 1 rather than if ERRORLEVEL 1, because the latter uses equal-or-greater logic, which would require you to reverse the order of the branching statements.
    • automatically validates the input (beeps if an invalid character is typed)

    See choice /? for more information.


    [1] However, you do need PowerShell if the command's output contains non-ASCII characters and you want the output redirection (>) to create UTF-16LE ("Unicode") files (Windows PowerShell) or (BOM-less) UTF-8 files (PowerShell (Core) v6+). Using > from cmd.exe results in OEM-encoded files, based on the console's code page, reported via chcp. Alternatively, you could switch the console code page to (BOM-less) UTF-8, via chcp 65001, but that wouldn't work with tree.com, because it is too old to support this code page. By contrast, it would work with the output from dir, for instance.