I have a batch file with this line of code in it:
choice /c:123 /n
This is basically a glorified pause that only proceeds if 1, 2, or 3 have been pressed. If I press any other button, It will beep. I've search around the internet for the file location of this beep, but I can't find anything.
Where is the file located? How can I get access this sound file?
Choice.exe imports the Beep function and that is where the sound comes from, it is not a wav file on disk, it is generated dynamically. You can run it in a debugger and set a breakpoint on that function to figure out the exact parameters it is using. On Windows 10 it uses (1500, 500).
You can get the beep sound using a little trick with the FORFILES command as documented on DosTips.com
#echo off
setlocal
::Define a Linefeed variable
set LF=^
::above 2 blank lines are critical - do not remove.
call :hexprint "0x07" rtnvar
FOR /L %%L IN (1,1,5) do echo %rtnvar%
pause
exit /b
:hexPrint string [rtnVar]
for /f eol^=^%LF%%LF%^ delims^= %%A in (
'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(%~1"'
) do if "%~2" neq "" (set %~2=%%A) else echo(%%A
exit /b
Related
I am using a batch file to rename all files in a folder into a numbered list. The code I use is as follow:
set /a Index=1
setlocal enabledelayedexpansion
for /f "tokens=*" %%f in ('dir /b') do (
echo %%f
echo !Index!
rename "%%f" "!Index!.*"
set /a Index+=1
pause
)
The result of the batch file is
G:\Directory A> (
echo
03.jpg
echo 1
rename "
03.jpg" "1.*"
set /a Index+=1
pause
)
03.jpg
1
The filename, directory name, or volume label syntax is incorrect.
Press any key to continue . . .
G:\Directory A> (
echo 04.jpg
echo 1
rename "04.jpg" "1.*"
set /a Index+=1
pause
)
04.jpg
1
The first result ALWAYS contains a line break at the beginning of the file name, which causes the RENAME command to fail. Can anyone tell me what is wrong with my code?
UPDATE
There is the folloging auto-run code set up in the Windows registry:
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"Autorun"="#chcp 65001>nul & prompt $d$s$s$t$_$p$g & cls"
After digging a bit with my batch file, I recognized that this is a problem with the Autorun option that I had set ages ago in Registry that look like this:
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"Autorun"="#chcp 65001>nul & prompt $d$s$s$t$_$p$g & cls"
Apparently the CLS command caused the weird line break to happen. After removing the CLS part from Autorun, the batch file works as it is intended to.
The finding described in the self-answer is very interesting albeit tremendously nasty!
The auto-run code contains the cls command, which sends a single form-feed character (FF, code0x0C) to the console that tells it to clear the screen (the character can be displayed by running cls > con in the console).
When executing cls within a for /F loop, the FF is captured: for /F %F in ('cls') do #echo/%F in the command prompt displays that character.
A for /F loop initiates a new cmd.exe instance to execute the given command line; this is done by preceding cmd /C to the command line.
With auto-run commands set up, they become executed within the for /F loop (due to the unfortunate lack of the /D option, which would prevent them to run).
The auto-run command line from the question has got cls involved, so for /F %F in ('rem') do #echo/%F captures a FF, even though the actual command rem does not return anything.
There are methods to suppress the FF character (note that the following code examples are intended to be placed in a batch-file rather than entered into the console):
Precede the desired command line by echo/& to append a line-break to a potential FF to have an extra line at the beginning and skip that line by for /F:
rem // Precede the desired command with `echo/` and skip the first line:
for /F "skip=1 delims=" %%I in ('echo/^& dir /B') do echo "%%I"
Retrieve a FF first and define it as the eol (end of line) character for for /F, then again prefix the desired command line with echo/& just like before:
rem // Retrieve the form-feed character and ignore lines beginning with a form-feed:
for /F delims^=^ eol^= %%F in ('echo/^& cls') do set "_FF=%%F"
rem // Precede the desired command with `echo/` and use form-feed as `eol` character:
for /F "delims= eol=%_FF%" %%I in ('echo/^& dir /B') do echo "%%I"
A more complex way needs to be gone when the auto-run code may write several arbitrary lines (that may even be empty). For this the number of said lines needs to be determined in order to become able to skip that number of lines later:
rem /* Determine the number of lines that the `AutoRun` code regurgitates, including empty ones;
rem the command line actually executed by `for /F` implicitly using `cmd /C` is as follows:
rem `chcp 437 > nul & echo/& cmd /C echo/| find /C /V ""`
rem this first returns a line-break, to have potential `AutoRun` text separated from the rest;
rem then another `AutoRun` text again with a terminal line-break is generated, but this time
rem piped into `find /C /V ""` in order to count the number of lines;
rem `chcp 437 > nul` is necessary to set the code page for the implicit `cmd.exe` instance,
rem because `find` (just like `more`) may have issues with some particulay Unicode code pages
rem (like 65001, which may be set by the `AutoRun` code): */
for /F %%C in ('chcp 437 ^> nul ^& echo/^& cmd /C echo/^| find /C /V ""') do set /A "SKIP=%%C" 2> nul
if %SKIP% gtr 0 (set "SKIP=skip=%SKIP%") else set "SKIP="
rem // Precede the desired command with `echo/` and skip as many lines as necessary:
for /F "%SKIP% delims=" %%I in ('echo/^& dir /B') do echo "%%I"
I am trying to stop screen flicker when it comes to my batch program that is used to display a text file on the screen. It has to update and the only way I have come up with is to loop the program and clear the screen.
This is my current code.
::Begin the refresh loop
::---------------------------------------------------------------
:Refresh
type "%ud%\ChatTerminal\Msg.txt
Sleep 1
cls
Goto Refresh
:Break Refresh
::---------------------------------------------------------------
::Refresh Loop Ends
::---------------------------------------------------------------
After some research I came to this post:
How do I remove flickering from a batch file animation?
The issue is that I would not know where to start with the implementation.
The escape character for VT sequences can be defined using:
For /F %%e in ('echo prompt $E^|cmd')Do set "\E=%%e"
Depending on the format and contents of each .txt file, flicker free animation could be as simple as returning the cursor to screen home between each 'frame':
<nul set /p "=%\E%[1;1H"
Edit
Should the source file/s be of differing line lengths or line counts, then each line needs to be read in and the VT sequence %\E%[K prepended to clear the remainder of the line and %\E%[0J after each file to clear the remainder of the console screen from the cursor location.
An example, which creates files to animate:
(Note: %\E%[E emits a line feed )
Anim.bat
#Echo off & CD /D "%~dp0"
For /f %%e in ('Echo Prompt $E^|cmd') Do set "\E=%%e"
<nul Set /P "=%\E%[?25l"
Set /A "delay=4", "Files=0","FC=1"
Setlocal EnableExtensions EnableDelayedExpansion
For %%i in (5 6 7 8 9 10 11 12 13 14 15 14 13 12 11 10 9 8 7 6 5)Do (
Set /A Files+=1
Call :CreateCube %%i "infile!Files!.txt"
)
For /L %%i in ()Do (
for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, tDiff=t2-t1"
if !tDiff! lss 0 set /a tDiff+=24*60*60*100
if !tDiff! geq !delay! (
Set /A "FC=FC %% Files + 1"
<nul Set /P "=%\E%[1;0H"
If !FC! GTR 10 (If !Offset! GTR 1 Set /A "Offset-=1")Else Set "offset=!FC!"
(For /f "Delims=" %%G in (infile!FC!.txt)Do <nul set /P "=%\E%[K%\E%[!offset!G%%G%\E%[E") > Con
<nul Set /P "=%\E%[0J"
set /a t1=t2
)
)
:CreateCube <size>
:# golfed script for outputting a shaded multi color cube
:# https://codegolf.stackexchange.com/a/224741/92319
#echo off&Cls&Set $=Set &CHCP 65001 > nul
If "%~1"=="" (Echo(%~n0 Integer Outfile.ext&Exit /B)
If "%~2"=="" (Echo(%~n0 Integer Outfile.ext&Exit /B)
(<Nul Set /p "=%\E%7")>"%~2"
%$%/A x=%1,h=x*2,z=0
%$%F=For /L %%a in (1 1 &%$%P=^<nul set/p &%$%C= If %%y LEQ %1
((%f:a=y%!h!)Do (%$%/a w=x-z
%F%!w!)Do %P%"=%\E%7 "
%F%!z!)Do%C%(%P%"=%\E%[38;2;0;120;%%a0m_|")Else %P%"=%\E%[4m%\E%[38;2;120;0;%%a0m\\%\E%[0m"
%F%%1)Do%C%(%P%"=%\E%[38;2;120;0;%%a0m▲▼")Else %P%"=%\E%[38;2;0;120;%%a0m_\"
%C:EQ=SS%(%$%/A z+=1)Else%C:If=If not%%$%/A z-=1)&Echo(%\E%[0m))>"%~2"
Note: the time elapsed operation used for framerate originates from Dave Benhams snake.bat
Implementation of framerate control in a repeating for /l infinate loop is strongly recommended to facilitate a smooth animation - failure to do so will result in the animation appearing jagged / choppy as it occurs at a pace the eye cant follow
T3RR0R's solution overwrites existing lines without deleting the rest of the old line. So when the new line is shorter, the rest of the old line keeps showing.
That could be solved by writing the file line by line, deleting the rest of the line. Sadly that slows things down and thus re-introduces the flicker (at least for files with more than one line).
As an alternative, only write the file, if it has changed. It still flickers, but now just when the file is updated. After displaying the file, unset the archive attribute. Whenever Windows writes to the file, it sets the attribute again, which we use to determine if the file has changed.
#echo off
set "file=%ud%\ChatTerminal\Msg.txt"
:loop
attrib "%file%"|findstr /b "A" >nul && (
cls
type "%file%"
attrib "%file%" -a
)
timeout 1 >nul
goto :loop
Bonus: this doesn't use Escape codes, so it runs on every Windows version (possibly there are a few deprecated Windows versions that didn't have timeout by default, but it can be replaced with ping when needed)
Seems like all you are trying to do is TAIL a file and print the those new lines to the screen. You can use this method to accomplish that.
#echo off
call :Read <"file.txt"
GOTO :EOF
:Read
set "line="
set /p "line="
if defined line (
echo %line%
)
goto :Read
The Issue: Group policies don;t allow me to change the lock screen to slideshow or spotlight but i am local admin on the pc and by replacing C:\Windows\Web\Screen\Screen.jpg i can change the lock screen picture.
Solution: create a batch/CMD/PS script that runs every xx minutes and copies a random picture from a source folder to replace C:\Windows\Web\Screen\Screen.jpg
i found a possible script in this article that could work but how do i modify it for my purpose and if i schedule it in task scheduler to run every 30 minutes would a Batch file run in the background without interference or would a CMD script or Powershell script be a better solutions?
see code below:
#echo off & setlocal
set "workDir=C:\source\folder"
::Read the %random%, two times is'nt a mistake! Why? Ask Bill.
::In fact at the first time %random% is nearly the same.
#set /a "rdm=%random%"
set /a "rdm=%random%"
::Push to your path.
pushd "%workDir%"
::Count all files in your path. (dir with /b shows only the filenames)
set /a "counter=0"
for /f "delims=" %%i in ('dir /b ^|find "."') do call :sub1
::This function gives a value from 1 to upper bound of files
set /a "rdNum=(%rdm%*%counter%/32767)+1"
::Start a random file
set /a "counter=0"
for /f "delims=" %%i in ('dir /b ^|find "."') do set "fileName=%%i" &call :sub2
::Pop back from your path.
popd "%workDir%"
goto :eof
:: end of main
:: start of sub1
:sub1
::For each found file set counter + 1.
set /a "counter+=1"
goto :eof
:: end of sub1
:: start of sub2
:sub2
::1st: count again,
::2nd: if counted number equals random number then start the file.
set /a "counter+=1"
if %counter%==%rdNum% (
:: OUTPUT ALERT BOX with FILENAME
MSG * "%fileName%"
)
goto :eof
:: end of sub2
IMO PowerShell is by far superior to batch in this case
dir C:\source\folder\*.jpg |Get-Random|Copy -Dest C:\Windows\Web\Screen\Screen.jpg -Force
You might wrap it in a batch/cmd line
powershell -Nop -C "dir C:\source\folder\*.jpg |Get-Random|Copy -Dest C:\Windows\Web\Screen\Screen.jpg -Force"
I need to process some audio files. Each file must go through multiple sequential steps, for which I've written a batch file. But I want all the files in the folder to be processed in parallel, for speed. So I've written another batch file which calls the first, in a loop. But when I do that, I end up with multiple command windows, which stay open even when the batch file has closed.
In order of preference, how can I either (a) not have the windows open at all, or (b) have the windows minimised then close when finished; or (c) have the windows open then close when finished.
for %%I in (*.mp3) DO (
start convert-mp3-to-m4b.bat "%%I"
)
I've managed to achieve (c), with start cmd /c convert-mp3-to-m4b.bat "%%I" /B, but that was more by luck than judgement.
With the help of #Stephan I've ended up with this:
for %%Z in (*.mp3) DO (
start "converting-audio" /min cmd /c convert-mp3-to-m4b.bat "%%Z"
)
This starts the windows minimised, and closes them after processing. I was also glad of the max <n> trick, although I had to adapt the code a bit. In case it's helpful to anyone else, my script now looks like this:
#echo off
setlocal enabledelayedexpansion
set count=0
set max=4
for %%Z in (*.mp3) DO (
call :loop
start "converting-audio" /min cmd /c convert-mp3-to-m4b.bat "%%Z"
)
goto :eof
:loop
for /f "tokens=* USEBACKQ" %%G IN (`tasklist /fi "windowtitle eq converting-audio" ^| find "cmd.exe" /C`) do ( SET "count=%%G" )
if !count! GEQ !max! call :loop
This processes the files four at a time, and works brilliantly.
Alright, I'm new to scripting and I'm trying to edit a batch script file that sends an email when a file with an extension of .ecl is in a folder longer than 5 min or so. But there are other files with a .ecl.part extension that get flagged and it sends an email instead of the .ecl files. I'm curious if there is something I can add so that it will send an email when there are .ecl files in the folder for more than 5 min and ignore the .ecl.part files. I read one for someone with Linux who used [!(.extension to exclude)].extension not to exclude, I'm just wondering if this will work for my windows batch script. If it will work do I add it just like that or do I add it like this .extension not to exclude[!(.extension to exclude)]
Here is the part of the script in question:
for /f "tokens=1-5 delims=:, " %%a in ('forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime"') do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
There is more of the script, I didn't set this up, and the person who did isn't being very helpful which is why I came here.
#ECHO OFF
SETLOCAL
SET savearea=c:\destdir
SET emldir=c:\sourcedir
ECHO.>"%savearea%\emlfiles.new"
DIR /b /a-d /on "%emldir%\*.eml" >>"%savearea%\emlfiles.new"
IF NOT EXIST "%savearea%\emlfiles.old" GOTO noold
FOR /f "usebackqdelims=" %%i IN ("%savearea%\emlfiles.new") DO (
FINDSTR /b /e "%%i" "%savearea%\emlfiles.old" >NUL
IF NOT ERRORLEVEL 1 (ECHO %%i is MORE than 5 minutes old)
)
:noold
MOVE /y "%savearea%\emlfiles.new" "%savearea%\emlfiles.old" >nul
GOTO :eof
This script saves in %savearea% a sorted basic filelist of the *.eml files in %emldir% then compares the new list to the previous version. If the same filename appears in both, it will generate the message %%i is MORE than 5 minutes old
So - all you need to do is point emldir to wherever your .eml files reside, savearea to some safe directory, replace the message ECHOing with an email-sending command of your liking and schedule it to run each 5 minutes using task scheduler.
Although in my testing I find this not to be the case, it sounds like forfilesis evaluating wildcards against 8.3 short filenames on your computer. You know how if you're in a directory containing both .doc and .docx files and you do a dir *.doc, the .docx files will be listed as well? Same sort of thing.
So *.ecl is matching your .ecl.part files because in 8.3 notation they've got a .ecl extension. You could either make sure %fnam:~-4%==.ecl, enclosing most of the guts of your for loop within an if statement; or you can use find or findstr to filter the output of forfiles as captured by the for loop. Something like this:
for /f "tokens=1-5 delims=:, " %%a in (
'forfiles /p z: /d +0 /s /m *.ecl /c "cmd /c if #isdir==FALSE echo #file,#ftime" ^| find /v /i ".part"'
) do (
set fnam=%%a
set fhr=%%b
set fmin=%%c
set fsec=%%d
set fampm=%%e
if "!fampm!" == "PM" if "!fhr!" neq "12" (set /a "fhr=!fhr!+12")
rem etc.
Since find /v prints lines not matching its search, that should effectively filter out the .ecl.part files. find /v works like grep -v in Linux.
You know, since my test cases don't seem to match the symptom you're describing, I am very curious to know whether simply replacing if #isdir==FALSE with if #ext==\"ecl\" would also prevent the .ecl.part files from being included. But if you don't feel like experimenting to satisfy my curiosity, I totally understand.