tsgsOFFICIAL
tsgsOFFICIAL

Reputation: 59

Batch file variables won't show up with echo

So I am tired of Spotify ads. So I wanted to create my own private music player.

But I ran into a problem as you will see later.

Here you get the choice of auto (basically a play list) or manual (only plays a single song).

But I removed this part of the code because it was working fine and was needless here.

@echo off
:auto
echo Now pick a song to start it off.

I removed the song names for copyright reasons.

echo.
echo Type 1 for song number one
echo Type 2 for song number two
echo Type 3 for song number three
echo Type 4 for song number four
echo Type 5 for song number five
echo.
set /p songID=Enter songID: 
if %songID%==1 goto Auto1
if %songID%==2 goto Auto2
if %songID%==3 goto Auto3
if %songID%==4 goto Auto4
if %songID%==5 goto Auto5

This is where I put the variables below.

And they are the trouble makers!

set song1=Song name 1
set song2=Song name 2
set song3=Song name 3
set song4=Song name 4
set song5=Song name 5

I kept all of the variables. I just removed the bottom of the code.

But it looks the same just :Auto2 and so on.

The set /a x=x is how long the song is and is used to create a timer.

So the song will end at the end of the song. ;)

And :POSSA1 and :POSA1 is creating the timer:

:Auto1
cls
start  %user%\Downloads\Songs\"Song name 1.mp3"
set /a x=248

:POSSA1
if %x%==1 goto POSA1
if %x% gtr 0 (
    echo Now playing %song1%
    echo.
    echo %x% Seconds
    choice /n /c yn /t 1 /d y >nul
    set /a x-=1
    cls
    goto POSSA1
)

:POSA1
if %x% gtr 0 (
    echo Now playing %song1%
    echo.
    echo %x% Second
    choice /n /c yn /t 1 /d y >nul
    set /a x-=1
    cls
    goto POSSA1
)

:end
cls
taskkill /F /IM WMPlayer.exe
pause>nul

So what am I doing wrong?

Upvotes: 0

Views: 2141

Answers (1)

Mofi
Mofi

Reputation: 49086

The first mistake is on line:

start  %user%\Downloads\Songs\"Song name 1.mp3"

In general the entire file name with path should be enclosed in double quotes and not just parts of like the name of the file only. Run in a command prompt window cmd /? and read all output help pages carefully.

And as it can be read by running in a command prompt window start /?, the first string in double quotes is interpreted by command START as optional title which very often requires to explicitly specify a title even if it is just an empty title, i.e. just specifying "". So the correct command line would be:

start  "" "%user%\Downloads\Songs\Song name 1.mp3"

Next don't use an arithmetic expression to assign a number to an environment variable which means don't use set /a x=248. It is better to use set "x=248".

Environment variables are always of type string. It is not possible to create environment variables of type integer. For the line set /a x=248 the Windows command processor converts first the string 248 into an integer using C function strtol and next converts the number back to a string to assign it to environment variable x. It is of course more efficient to assign the number string directly as string to the environment variable.

Further it is advisable to enclose the parameter of command SET which is variable=string also always in double quotes. For an explanation see the answers on How to set environment variables with spaces? and Why is no string output with 'echo %var%' after using 'set var = text' on command line?

That means in your batch code fragments:

set "song1=Song name 1"
set "song2=Song name 2"
set "song3=Song name 3"
set "song4=Song name 4"
set "song5=Song name 5"

set /p "songID=Enter song ID: "

Run in a command prompt window set /? and read all output help pages. You can read there something about delayed expansion. Delayed environment variable expansion is needed always when an environment variable is defined or modified within a command block starting with ( and ending with matching ) and the value of the environment variable is referenced in same command block.

The reason is that all environment variable references with %VariableName% from first ( to matching ) are replaced immediately by current string value of the reference environment variable before the command is even executed which is usually either the command FOR or IF. And this preprocessed command block is not further updated.

This variable expansion behavior can be watched by

  • removing all @echo off or echo off from batch file, commenting them out with command REM or modifying off to on,
  • opening a command prompt window,
  • running from within the command prompt window the batch file either from directory containing the batch file or by entering the file name of the batch file with full path and best also with file extension enclosed in double quotes.

Now with running the batch file from within a command prompt window with echo mode enabled instead of double clicking on it with echo mode disabled, it can be seen what the Windows command processor really executes after preprocessing each command line respectively command block. And on an error the error message can be also seen because the console window remains open even if a syntax error is encountered by the Windows command processor.

That is the method even advanced batch file coders use to debug batch code during development.

Although the code snippets in question are not helpful to reproduce the problem, I think nothing is output by echo Now playing %song1% as the line set song1=Song name 1 is in the same command block starting anywhere above with ( and ending anywhere below ) and therefore delayed expansion is needed.

Run in a command prompt window also setlocal /? and endlocal /? for help on those two commands also needed on using delayed expansion.

As it can be seen on reading this answer, to get help on a command used in a batch file, simply run the command with parameter /? from within a command prompt window. It is recommended to make use of the built in help on developing a batch file.

Finally I would recommend putting the file names into a text file (play list file) and use command FOR to process them (output, select one for playing, etc.). Read more about command FOR by running in a command prompt window for /?.


Demo code for coding the player with using a songs list file.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SongsListFile=C:\Temp\Song List.txt"
set "SongFileMissing=0"

if not exist "%SongsListFile%" goto ListFileError

cls
echo Pick a song to start it off.
echo.
echo      0 ... play all songs

rem Output all songs from song list without path and file extension.
rem The song number is right aligned with 3 characters width which
rem means working for song numbers 1 to 999.

set "SongNumber=0"
for /F "usebackq delims=" %%I in ("%SongsListFile%") do (
    set /A SongNumber+=1
    set "SongOption=  !SongNumber!"
    set "SongOption=!SongOption:~-3!"
    echo    !SongOption! ... %%~nI
)
echo.

rem Define as default value 0 for playing all songs in case of
rem user just hits key RETURN or ENTER and prompt user for number.
set "SongSelected=0"
set /P "SongSelected=Enter song number (default: %SongSelected%): "
echo.

rem Play all songs if a string was entered by the user not consisting
rem of only digits, i.e. the entered string is not a number.
for /F "delims=0123456789" %%I in ("!SongSelected!") do goto PlayAll

rem Numbers with leading 0s could be interpreted as octal numbers by
rem Windows command processor and therefore better make sure that the
rem number string does not have leading zeros. On a number like 0, 00,
rem 000, ... play all songs.

:RemoveLeadingZeros
if not "%SongSelected:~0,1%" == "0" goto CheckMaxNumber
set "SongSelected=%SongSelected:~1%"
if not "%SongSelected%" == "" goto RemoveLeadingZeros
goto PlayAll

rem Windows command processor interprets numbers as signed 32-bit integers
rem which limits the range from -2147483648 to 2147483647 whereby only the
rem positive range is of interest here at all. The entered number string
rem could be longer than what Windows command processor supports. Every
rem number with more than 9 digits is interpreted as invalid which reduces
rem the valid number range here from 1 to 999999999 which should be always
rem enough. And of course the entered number should not be greater than
rem the number of song file names in songs list.

:CheckMaxNumber
if not "%SongSelected:~9,1%" == "" goto PlayAll
if %SongSelected% GTR %SongNumber% goto PlayAll

rem For playing a single song skip all lines above the line with the
rem song file name to play, play the selected song file and then exit
rem the loop without processing the other lines in songs list file.
rem skip=0 results in a syntax error and therefore it is necessary to
rem define the entire skip option as an environment variable if needed
rem because any other than first song in songs list file should be played.

set "SkipOption="
set /A SongSelected-=1
if not "%SongSelected%" == "0" set "SkipOption= skip=%SongSelected%"

if not exist "%SongsListFile%" goto ListFileError
for /F "usebackq%SkipOption% delims=" %%I in ("%SongsListFile%") do (
    call :PlaySong "%%~fI"
    goto EndPlayer
)

rem Output error message if songs list file does not exist
rem checked every time before reading the lines from this file.

:ListFileError
echo Error: The songs list file "%SongsListFile%" does not exist.
set "SongFileMissing=1"
goto EndPlayer


rem This is a subroutine embedded in the player's batch file used
rem to play the song passed to the subroutine with first argument.

:PlaySong
if not exist "%~1" (
    echo Error: Song file "%~1" does not exist.
    set "SongFileMissing=1"
    goto :EOF
)

echo Playing now song %~n1 ...

rem Insert here the code used to play the song.

rem This command results in exiting subroutine and processing of batch
rem file continues on the line below the line calling PlaySong.
goto :EOF


:PlayAll
if not exist "%SongsListFile%" goto ListFileError
for /F "usebackq delims=" %%I in ("%SongsListFile%") do call :PlaySong "%%~fI"

:EndPlayer
echo.
if not "%SongFileMissing%" == "0" (
    endlocal
    pause
) else endlocal

Read the comments which are the lines starting with command REM, especially the line

rem Insert here the code used to play the song.

This line must be replaced by the code to play the song file "%~1".

The songs list file C:\Temp\Song List.txt can contain the names of the song files with or without path. For example:

First song.mp3
C:\Temp\Another song.mp3
Album 1 - Last song .mp3

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • cls /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?

Upvotes: 1

Related Questions