cmd /q not working as expected - windows

I want to start a command prompt but don't want any output from it. So I am starting it as -
cmd /q dir
which works fine but one cmd.exe doesn't exit. If I use this-
cmd /q /c dir
I can see output of dir command which I don't expect to see

The /Q option does not disable output, it only turns ECHO OFF. It is not normally needed, but there are occasions where it becomes useful.
To disable all non-error output, simply redirect the stdout to nul (>nul or 1>nul). If you also want to disable error output, then stderr must also be redirected (2>nul).
>nul 2>nul cmd /c dir
Addendum
Andriy M has a good point with his comment on the question. You can probably execute your command directly without going through CMD. Redirection would still work the same.
>nul 2>nul yourCommand.exe

Related

Windows Batch File for loop on user dir

I need to create a batchfile to delete a specific file in the users appdata dir. The batchfile is executed as localsystem.
I did test the following senarios:
Command Prompt as localsystem - this works
Command Prompt as admin - this works
Command Prompt as user - this works for all folders where the user has permissions
As soon as i put the for loop in a batch file, it dosent work anymore.
It also dosent matter in which context (User,admin,localsystem) i start it.
for /D %i in ("C:\Users\*") do del /Q /F "%i\AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
The exit code shows 255, which means to long error.
The error i get is the following:
C:\Windows\Scripts>sync_exeptionsiteslistandconfig_java.bat > output.txt
\Users\*") do del "i\AppData\LocalLow\Sun\Java\Deployment\deployment.properties" /Q /F was unexpected at this time.
Any help why the single line is working and a batchfile with this single line is not working is welcome.
Please also explain why it is not working. (I always run tasks as localsystem)
This may do what you want, but it only processes normal folders, not hidden etc.
Your problem may have been using %i within a batch script.
#echo off
for /D %%i in ("C:\Users\*") do del /Q /F "%%i\AppData\LocalLow\Sun\Java\Deployment\deployment.properties" 2>nul

How to supply console input ( yes / no ) as part of batch file on Windows.

I am writing a simple batch file (remove.bat) to remove a directory and all its subdirectories. The file contains the following command-
rmdir /S modules
where modules is the name of the non-empty directory.
I get the following message -
C:\...\bin>rmdir /S modules
modules, Are you sure (Y/N)?
How can I supply through the batch file the console input "Y" to the Y/N question above? Is there a command that can do this?
As others have pointed out, you should use the /Q option. But there is another "old school" way to do it that was used back in the day when commands did not have options to suppress confirmation messages. Simply ECHO the needed response and pipe the value into the command.
echo y|rmdir /s modules
I recommend using the /Q option instead, but the pipe technique might be important if you ever run into a command that does not provide an option to suppress confirmation messages.
Note - This technique only works if the command reads the input from stdin, as is always the case with cmd.exe internal commands. But this may not be true for some external commands.
Do rmdir /S for deleting a non-empty directory and do rmdir /Q for not prompting. Combine to rmdir /S /Q for quietly delete non-empty directories.
Use rmdir /S /Q modules
/Q suppresses the confirmation prompt.
You can do
rmdir /Q
Q is for quiet
If you are not dealing with a windows with a english/us locale you might need to retrieve the answers needed for your machine:
#echo off
setlocal
set "ans_yes="
set "ans_no="
set "ans_all="
copy /y nul # >nul
for /f "tokens=2-7 delims=[(/)]" %%a in ( '
copy /-y nul # ^<nul
' ) do if not defined ans_yes if "%%~e" == "" (
set "ans_yes=%%~a"
set "ans_no=%%~b"
set "ans_all=%%~c"
) else (
set "ans_yes=%%~a"
set "ans_no=%%~c"
set "ans_all=%%~e"
)
del /q #
set "ans_yes=%ans_yes: =%"
set "ans_no=%ans_no: =%"
set "ans_all=%ans_all: =%"
set "ans_y=%ans_yes:~0,1%"
set "ans_n=%ans_no:~0,1%"
set "ans_a=%ans_all:~0,1%"
endlocal & (
set "ans_y=%ans_y%"
set "ans_n=%ans_n%"
set "ans_a=%ans_a%"
)
echo %ans_y%|rmdir /s modules
YES.EXE
Yes is a fantastic tool that will continually answer Yes, No or whatever to any process that is asking for input.
If you run it by itself, it just outputs y + enter over and over. But that's not really what it's meant for. It's meant for piping into another program that is looking for a response to a prompt.
The simplest use case:
yes|rd temp /s
You can use yes.exe to output any argument or string: (stupid example warning):
yes hello world for a simple basic 10 PRINT "Hello World": GOTO 10
What it's really for:
It's meant for command line tools that can have a repetitive prompt but don't have a built-in /y or /n.
For example, you're copying files and keep getting the Overwrite? (Yes/No/All) prompt, you get stuck having to hammer to "N" key for No. Here's the fix:
yes n|copy * c:\stuff
How to get it?
This is just a small part of the GNU Core Utils for Windows, which provides the basic Linux commands to Windows people. VERY, VERY useful stuff if you write a lot of batch files.
If you have Git for Windows, you already have it, along with the rest of the GNU Core Utils. Check your PATH for it. It's probably in C:\Users\USERNAME\AppData\Local\Programs\Git\usr\bin
If you need to download the Windows binaries, they're available from a lot of different places, but the most popular is probably at https://cygwin.com/packages/summary/coreutils.html
I just want to add that, although not applicable to Rmdir, a force switch may also be the solution in some cases. So in a general sense you should look at your command switches for /f, /q, or some variant thereof (for example, Netdom RenameComputer uses /Force, not /f).
The echo pipe is a neat trick and very useful to keep around since you wont always find an appropriate switch. For instance, I think it's the only way to bypass this Y/N prompt...
Echo y|NETDOM COMPUTERNAME WorkComp /Add:Work-Comp
Link to nearly identical StackOverflow post

How do I make a Windows batch script completely silent?

There has been variants of this question asked for generations, but despite writing some quite complicated Windows scripts, I can't seem to find out how to make them actually silent.
The following is an excerpt from one of my current scripts:
#ECHO OFF
SET scriptDirectory=%~dp0
COPY %scriptDirectory%test.bat %scriptDirectory%test2.bat
FOR /F %%f IN ('dir /B "%scriptDirectory%*.noext"') DO (
del "%scriptDirectory%%%f"
)
ECHO
The result of this is:
C:\Temp> test.bat
1 file(s) copied.
File Not Found
Echo is off.
C:\Temp>
Whereas the "1 file(s) copied." is just annoying, the "File Not Found" makes the user think that something has gone wrong (which it hasn't - no files is fine).
To suppress output, use redirection to NUL.
There are two kinds of output that console commands use:
standard output, or stdout,
standard error, or stderr.
Of the two, stdout is used more often, both by internal commands, like copy, and by console utilities, or external commands, like find and others, as well as by third-party console programs.
>NUL suppresses the standard output and works fine e.g. for suppressing the 1 file(s) copied. message of the copy command. An alternative syntax is 1>NUL. So,
COPY file1 file2 >NUL
or
COPY file1 file2 1>NUL
or
>NUL COPY file1 file2
or
1>NUL COPY file1 file2
suppresses all of COPY's standard output.
To suppress error messages, which are typically printed to stderr, use 2>NUL instead. So, to suppress a File Not Found message that DEL prints when, well, the specified file is not found, just add 2>NUL either at the beginning or at the end of the command line:
DEL file 2>NUL
or
2>NUL DEL file
Although sometimes it may be a better idea to actually verify whether the file exists before trying to delete it, like you are doing in your own solution. Note, however, that you don't need to delete the files one by one, using a loop. You can use a single command to delete the lot:
IF EXIST "%scriptDirectory%*.noext" DEL "%scriptDirectory%*.noext"
If you want that all normal output of your Batch script be silent (like in your example), the easiest way to do that is to run the Batch file with a redirection:
C:\Temp> test.bat >nul
This method does not require to modify a single line in the script and it still show error messages in the screen. To supress all the output, including error messages:
C:\Temp> test.bat >nul 2>&1
If your script have lines that produce output you want to appear in screen, perhaps will be simpler to add redirection to those lineas instead of all the lines you want to keep silent:
#ECHO OFF
SET scriptDirectory=%~dp0
COPY %scriptDirectory%test.bat %scriptDirectory%test2.bat
FOR /F %%f IN ('dir /B "%scriptDirectory%*.noext"') DO (
del "%scriptDirectory%%%f"
)
ECHO
REM Next line DO appear in the screen
ECHO Script completed >con
Antonio
You can redirect stdout to nul to hide it.
COPY %scriptDirectory%test.bat %scriptDirectory%test2.bat >nul
Just add >nul to the commands you want to hide the output from.
Here you can see all the different ways of redirecting the std streams.
Just add a >NUL at the end of the lines producing the messages.
For example,
COPY %scriptDirectory%test.bat %scriptDirectory%test2.bat >NUL
Copies a directory named html & all its contents to a destination directory in silent mode.
If the destination directory is not present it will still create it.
#echo off
TITLE Copy Folder with Contents
set SOURCE=C:\labs
set DESTINATION=C:\Users\MyUser\Desktop\html
xcopy %SOURCE%\html\* %DESTINATION%\* /s /e /i /Y >NUL
/S Copies directories and subdirectories except empty ones.
/E Copies directories and subdirectories, including empty
ones. Same as /S /E. May be used to modify /T.
/I If destination does not exist and copying more than one
file, assumes that destination must be a directory.
/Y Suppresses prompting to confirm you want to overwrite
an
existing destination file.

How to suppress specific lines in Windows cmd output?

On Windows, I have written a simple bat script that calls another tool. However, this tool outputs a few specific debug lines when using certain options (seems to be a bug in the original code, which I can not/don't want to modify).
Is there a way to suppress lines output by a command that matches a certain pattern (like starting with DEBUG: )?
(FYIO: the tool is latexdiff.exe, and there are some print STDERR "DEBUG:... lines in the perl source code that are not conditional to the debug variable and printed everytime the --flatten option is used. I don't want to suppress stderr completely either.)
You could try the following:
latexdiff.exe 2>&1| findstr /v /b "DEBUG:"
The /v option basically turns the pattern around, i.e. findstr.exe will let everything through, not matching the pattern. The /b option simply says that the pattern should occur at the beginning of a line.
The 2>&1 redirects STDERR to STDOUT and is required because, as you said, the lines are written to STDERR, not STDOUT. Note that as a "side effect" all output now is written to STDOUT.
Update if there is other output on STDOUT that you need to have, you could do something like this
latexdiff.exe old.tex new.tex > diff.tex 2> latexdiff.stderr
type latexdiff.stderr | findstr /v /b "DEBUG:"
That is, redirect STDOUT to your diff file, redirect STDERR to some file. Afterwards, you just type the file to see error messages.
You might want to put that into a batch file of it's own, like so:
#echo off
setlocal
REM determine a suitable temporary filename
set error_file=%TEMP%\latexdiff.%RANDOM%.stderr
REM run actual diff and save its exit code for later
latexdiff.exe "%~1" "%~2" > "%~3" 2> "%error_file%"
set error_level=%ERRORLEVEL%
REM dump error messages
type "%error_file%" | findstr /v /b "DEBUG:"
REM remove temporary error file and exit with latexdiff's exit code.
del /q "%error_file%"
exit /b %error_level%
You can then call it like: latexdiff_wrapper.cmd old.tex new.tex diff.tex. Appart from using temporary files, the downside is, that error messages will not appear while processing, but at the very end. If that is not an issue, it shouldn't because the diff should be fast, you might find that solution useful.

Detecting how a batch file was executed

Assuming Windows, is there a way I can detect from within a batch file if it was launched from an open command prompt or by double-clicking? I'd like to add a pause to the end of the batch process if and only if it was double clicked, so that the window doesn't just disappear along with any useful output it may have produced.
Any clever ways to do this? I'm looking for solutions I could rely on to work on a machine that was configured more or less with default settings.
I just ran a quick test and noticed the following, which may help you:
When run from an open command prompt, the %0 variable does not have double quotes around the path. If the script resides in the current directory, the path isn't even given, just the batch file name.
When run from explorer, the %0 variable is always enclosed in double quotes and includes the full path to the batch file.
This script will not pause if run from the command console, but will if double-clicked in Explorer:
#echo off
setlocal enableextensions
set SCRIPT=%0
set DQUOTE="
#echo do something...
#echo %SCRIPT:~0,1% | findstr /l %DQUOTE% > NUL
if %ERRORLEVEL% EQU 0 set PAUSE_ON_CLOSE=1
:EXIT
if defined PAUSE_ON_CLOSE pause
EDIT:
There was also some weird behavior when running from Explorer that I can't explain. Originally, rather than
#echo %SCRIPT:~0,1% | findstr /l %DQUOTE% > NUL
if %ERRORLEVEL% EQU 0 set PAUSE_ON_CLOSE=1
I tried using just an if:
if %SCRIPT:0,1% == ^" set PAUSE_ON_CLOSE=1
This would work when running from an open command prompt, but when run from Explorer it would complain that the if statement wasn't correct.
Yes. Patrick Cuff's final example almost worked, but you need to add one extra escape, '^', to make it work in all cases. This works great for me:
set zero=%0
if [^%zero:~0,1%] == [^"] pause
However, if the name of the batch file contains a space, it'll be double quoted in either case, so this solution won't work.
Don't overlook the solution of having two batch files:
abatfile.bat and abatfile-with-pause.bat
The second simply calling the first and adding a pause
Here's what I use :
rem if double clicked it will pause
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
I use a parameter "automode" when I run my batch files from scripts.
set automode=%7
(Here automode is the seventh parameter given.)
Some code follows and when the file should pause, I do this:
if #%automode%==# pause
One easy way to do it is described here:
http://steve-jansen.github.io/guides/windows-batch-scripting/part-10-advanced-tricks.html
There is little typo in the code mentioned in the link. Here is correct code:
#ECHO OFF
SET interactive=0
ECHO %CMDCMDLINE% | FINDSTR /L /I %COMSPEC% >NUL 2>&1
IF %ERRORLEVEL%==0 SET interactive=1
ECHO do work
IF "%interactive%"==1 PAUSE
EXIT /B 0
Similar to a second batch file you could also pause if a certain parameter is not given (called via clicking).
This would mean only one batch file but having to specify a -nopause parameter or something like that when calling from the console.
crazy idea: use tasklist and parse it's results.
I've wrote in a test batch file:
tasklist > test.out
and when I double-clicked it, there was an additional "cmd.exe" process just before the tasklist process, that wasn't there when the script was run from command line (but note that might not be enough if someone opens a command line shell and then double-click the batch file)
Just add pause regardless of how it was opened? If it was opened from command prompt no harm done apart from a harmless pause. (Not a solution but just thinking whether a pause would be so harmful / annoying )

Resources