In a CMD .BAT file, how to turn echo off locally i.e. such that upon exit, echo state is restored?
#ECHO Off
SETLOCAL
::call the sub
CALL q25232315s
:: just a command for something-to-do
DIR u:
GOTO :EOF
If this is the main routine, then if this is the called routine:
#SETLOCAL
#echo>u:\tempfile.txt
#FOR /f "tokens=3delims=. " %%a IN (u:\tempfile.txt) DO #SET state=%%a&#DEL u:\tempfile.txt
#ECHO OFF
:: just a command for something-to-do
DIR u:\destdir
ECHO %state%&EXIT /b
It would appear to restore the echo state to the caller whilst keeping mum about its own activities.
Related
I would like my script to execute the pause command whether the script completes, or if an error/exception if thrown.
Basically, I want the script to behave as if I placed
setlocal enabledelayedexpansion
REM Keep cmd window open until script finishes in case of error
if not defined in_subprocess (cmd /k set in_subprocess=y ^& %0 %*) & exit )
at the top of the script, but give the Press any key to continue . . . option to exit/close the cmd window.
Thanks! Here is what I ended up with for general use:
#echo off
REM ##########################################################################################################
REM Functions
REM ##########################################################################################################
goto :main
REM ##########################################################################################################
REM run_and_keep_window_open_with_press_key_to_close_window
REM ##########################################################################################################
:run_and_keep_window_open_with_press_key_to_close_window
echo "hi there"
sfgsdgfdfg
goto :eof
REM ##########################################################################################################
REM Main
REM ##########################################################################################################
:main
call :run_and_keep_window_open_with_press_key_to_close_window
if %errorlevel% EQU 0 (pause) else (color CF && pause)
Ok. I have this batch file that is designed to remove every file and folder from inside a folder that may or may not be present. The basic structure Follows:
#echo off
If EXIST c:\MyDirectory\(
chdir c:\MyDirectory\
echo %CD%
echo %0
echo %~dp0
rem ... This removes everything from the folder....
for /F "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
)
The reason for the echoes in I'd like to be able to ensure the batch script has actually changed the path to MyDirectory and is deleting the correct files(we had an incident earlier that I'm kindof in hot water for where the script didn't change paths and deleted everything from one of our docs folders).
The echoes return the either the name of the batch file itself, or the path the batch file was run from,instead of "c:\MyDirectory\". So in my case it's from c:\Testing\ (a dummy directory I created to avoid a second oops).
Is there a way to get the currently active directory from inside a batch script, so that I can verify the directory I'm about to empty??
Try this:
#echo off
setlocal EnableDelayedExpansion
If EXIST c:\MyDirectory\(
chdir c:\MyDirectory\
echo !CD!
pause
rem ... This removes everything from the folder....
for /F "delims=" %%i in ('dir /b') do (rmdir "%%i" /s/q || del "%%i" /s/q)
)
Since you're in an if statement you should use setlocal EnableDelayedExpansion and use ! instead of % for variables.
To nuke the contents of a directory, use this shell script (batch file):
#echo off
setlocal enableextensions
if {%1}=={} goto :HELP
if {%1}=={/?} goto :HELP
goto :START
:HELP
echo Usage: %~n0 directory-name
echo.
echo Empties the contents of the specified directory,
echo WITHOUT CONFIRMATION. USE EXTREME CAUTION!
goto :DONE
:START
pushd %1 || goto :DONE
rd /q /s . 2> NUL
popd
:DONE
endlocal
OK. My question pretty much explains itself. Is it possible to creat a batch file, that when executed will create another batch file via copy con command?
Something like:
#echo off
copy con file.bat
#echo off
echo hallo
exit
^Z
start file.bat
The only problem I encountered trying to do this, was that you manualy need to hit Enter after ^Z, and I cannot find any kind of cmd command to replicate that.
Does anyone know if such a thing is possible? Or is there any other way for a batch file to re-create another batch file or itself?
Thank you.
It may be possible to issue an escape code for ^Z and do it with copy con but why would you?
Just just normal redirection of the echo command.
Like this:
#echo off
echo Generating batch file
echo echo Hello world > hello.bat
echo Now running batch file
echo ----------
call hello.bat
echo ----------
echo Ta-da!
There are multiple ways to create a Batch file from inside another one. The methods that use echo batch code requires to escape the special characters that may appear in the "batch code". There are other methods that consist in read lines from the Batch file itself and then output such lines to the created file; in this case, the lines may have pure Batch code even if they contains special characters.
The method you used in your example is similiar to Unix heredoc feature, that is:
tr a-z A-Z << END_TEXT
one two three
uno dos tres
END_TEXT
There are several ways to simulate a "Unix heredoc" in Batch; for example this one:
#echo off
rem Definition of heredoc macro
setlocal DisableDelayedExpansion
set LF=^
% Don't remove this line 1/2 %
% Don't remove this line 2/2 %
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set heredoc=for %%n in (1 2) do if %%n==2 (%\n%
for /F "tokens=1,2" %%a in ("!argv!") do (%\n%
if "%%b" equ "" (call :heredoc %%a) else call :heredoc %%a^>%%b%\n%
endlocal ^& goto %%a%\n%
)%\n%
) else setlocal EnableDelayedExpansion ^& set argv=
rem Heredoc syntax:
rem
rem %%heredoc%% :uniqueLabel [outfile]
rem contents
rem contents
rem ...
rem :uniqueLabel
rem For example:
%heredoc% :endBatch file.bat
#echo off
echo hallo
exit /B
:endBatch
echo Calling created file:
call file.bat
echo Return from created file
goto :EOF
rem Definition of heredoc subroutine
:heredoc label
set "skip="
for /F "delims=:" %%a in ('findstr /N "%1" "%~F0"') do (
if not defined skip (set skip=%%a) else set /A lines=%%a-skip-1
)
for /F "skip=%skip% delims=" %%a in ('findstr /N "^" "%~F0"') do (
set "line=%%a"
echo(!line:*:=!
set /A lines-=1
if !lines! == 0 exit /B
)
exit /B
Isn't it better to do it like this? Maybe I don't know what you mean, but I think this can help you:
#echo off
>newbatch.bat (
echo #echo off
echo echo It works!
echo echo Hope it helped you :)
echo pause >nul
)
run newbatch.bat
I like to have a typical "usage:" line in my cmd.exe scripts — if a parameter is missing, user is given simple reminder of how the script is to be used.
The problem is that I can't safely predict whether potential user would use GUI or CLI. If somebody using GUI double-clicks this script in Explorer window, they won't have chance to read anything, unless I pause the window. If they use CLI, pause will bother them.
So I'm looking for a way to detect it.
#echo off
if _%1_==__ (
echo usage: %nx0: filename
rem now pause or not to pause?
)
Is there a nice solution on this?
You can check the value of %CMDCMDLINE% variable. It contains the command that was used to launch cmd.exe.
I prepared a test .bat file:
#Echo Off
echo %CMDCMDLINE%
pause
When run from inside of open cmd.exe window, the script prints "C:\Windows\system32\cmd.exe".
When run by double-clicking, it prints cmd /c ""C:\Users\mbu\Desktop\test.bat" "
So to check if your script was launched by double-clicking you need to check if %cmdcmdline% contains the path to your script. The final solution would look like this:
#echo off
set interactive=1
echo %cmdcmdline% | find /i "%~0" >nul
if not errorlevel 1 set interactive=0
rem now I can use %interactive% anywhere
if _%1_==__ (
echo usage: %~nx0 filename
if _%interactive%_==_0_ pause
)
Edit: implemented fixes for issues changes discussed in comments; edited example to demonstrate them
:: exit if not interactive
echo %CMDCMDLINE% | find /i "/c"
if not ERRORLEVEL 1 goto:eof
Here, I wrote something...
Usage.bat
#echo off
if arg%1==arg goto help
goto action
:action
echo do something...
goto end
:help
set help1=This is Help line 1.
set help2=This is Help line 2.
cmd.exe /k "echo %help1% &echo %help2%"
goto end
:end
It's not perfect, but it works! :D
-joedf
This is only using the internal command. so effectively....
EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%~f0=!" pause >nul
or
if not "!cmdcmdline!" == "!cmdcmdline:%~f0=!" pause >nul
DisableDelayedExpansion
if "%cmdcmdline%" neq "%cmdcmdline:%~f0=%" pause >nul
or
if not "%cmdcmdline%" == "%cmdcmdline:%~f0=%" pause >nul
Start your batch checking for %WINDIR% in %cmdcmdline% like this:
echo "%cmdcmdline%" | findstr /ic:"%windir%" >nul && (
echo Interactive run of: %0 is not allowed
pause
exit /B 1
)
Please use findstr
echo %cmdcmdline% | findstr /ic:"%~f0" >nul && ( pause >nul )
or
setlocal EnableDelayedExpansion
.
.
echo !cmdcmdline! | findstr /ic:"%~f0" >nul && ( pause >nul )
.
.
endlocal
This is always worked...
for internal command
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~0,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
or
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~28,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
You can compare the different thing, but this is only worked within EnableDelayedExpansion. and I don't think that this will be always worked, cause windows version, etc...
Similar approach...
setlocal
set startedFromExplorer=
echo %cmdcmdline% | find /i "cmd.exe /c """"%~0""" >nul
if not errorlevel 1 set startedFromExplorer=1
...
if defined startedFromExplorer pause
goto :EOF
setlocal EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%comspec%=!" ( pause>nul )
Test is done in Windows 10. Using %windir%, it is a little dangerous or ambiguous. So %comspec% is super safe.
I created a .bat file with the below lines
cd C:\MyFolder
d:
findstr "Apple" C:\log.txt |findstr "red" > red_apples.txt
SLEEP 3600
GOTO START
When the bat is executed, the SLEEP is not working and the commands are running continously.
Is there anything wrong with the code? Please help !
I don't believe Windows has a sleep, you can emulate it with ping, as shown in this example chkwait.cmd script:
#setlocal enableextensions enabledelayedexpansion
#echo off
echo %time%
call :waitfor 20
echo %time%
endlocal
goto :eof
:waitfor
setlocal
set /a "t = %1 + 1"
>nul ping 127.0.0.1 -n %t%
endlocal
goto :eof
The call :waitfor 20 in the above script will wait for twenty seconds:
pax> chkwait
10:18:13.42
10:18:33.51
SLEEP does not exist in windows batch script. You would have create your own Sleep wrapper EXE and call that from the batch. Or use the clever trick from #paxdiablo above.