I'm working on a - I thought - simple script, which can install multiple programs.
So let's see, this is my directory with the mandatory files.
C:\variables.ini
C:\programs.txt
C:\update.cmd
C:\scan.cmd
C:\storage\ *.exe
Example for *.exe is "scribus-1.4.4-windows-x64.exe"
variables.ini contains
prog=C:\programs.txt
programs.txt contains
scribus-1.4.4-windows-x64.exe
scan.cmd contains
dir C:\storage /b /a-d > programs.txt
Now the problem: update.cmd
#ECHO OFF & SETLOCAL
REM Read variables
for /f %%i in (C:\variables.ini) do set %%i
cd C:\storage\
for /f %%i in %prog% do %%i /Q /S
ping localhost -n 5 > nul
del %%i
ping localhost -n 5 >nul
exit
How works the update.cmd?
I've a main .cmd from there I call multiple .cmd files which do several things. As you see, I run in the first place the scan.cmd. It scans the c:\storage\ dir and write the content into c:\programs.txt. In the variables.ini is the programs.txt file as %prog% variable embedded. Now I run update.cmd and it takes the first variable program from the programs.txt, in this case scribus, and start the install with /silent and /quiet flag (some programms use /s and others /q, but not both, maybe a possible bug, but I had no better idea). After the install it waits for 5 seconds and remove the .exe file. If there are other executables, then the script start again til the storage dir is empty.
I hope you understand me... I tried some other ways, but I failed.
So I tried it without the variables file and executed the scan command inside the update.cmd
#ECHO & SETLOCAL
cd C:\storage\
for /F %%i in ('dir C:\storage /b /a-d') do set %%i
%%i /Q /S
ping localhost -n 5 >nul
pause
There I get some errors, that scribus is no environment variable. I don't know why it should be anyone? I tried google and read many tutorials and threads about for-loops, but not one person executed a setup file from a variable.
Does anyone know a way how I can fix this?
Many thanks in advance!!
Noting that your paths are horrible: don't install things into the root of the system drive.
As is cmd.exe: PowerShell is the future and vastly more powerful. And using ping for a delay (it sends the next ping as soon as the previous received: so not a good timing mechanism).
But I think all you need to do it launch executables is
start /wait command
which will not return until command has finished.
You also seem to be trying to run multiple commands in a for loop in cmd, this is possible:
for /F %%i in ('dir C:\storage /b /a-d') do set %%i && %%i /Q /S
using && to separate the commands (it is not clear why you have set %%i: it will just list variables with the name, you're not setting a value).
Related
I am using this command line
for /r /d %F in (.) do #dir /b "%F" | findstr "^" >nul || echo %~fF
to find empty folders.
However this command is working for subfolders too. How can I change it to exclude the sub folders?
Remove the /r from the command, use this:
for /d %F in (*) do #dir /b "%F" | findstr "^" >nul || echo %~fF
As this is clearly for the current directory, I would off a slightly different alternative. This is because For /D doesn't pick up every directory, it ignores hidden ones, and Dir /B alone, does not select every file and directory.
For /F "EOL=? Delims=" %G In ('Dir /B/AD') Do #Dir /B/A "%G" 2>NUL|%__AppDir__%find.exe /V "">NUL||Echo %G
If you prefer a relative path for your results, just use Echo .\%G instead
The answer uses 2>NUL to redirect any File Not Found error messages to the NUL device. It also uses find.exe as an alternative to findstr.exe, to ensure that the answer is less similar than the existing one, and because you don't really need its special functionality.
To get more information about the commands used, please open a cmd window, and enter the following commands as necessary:
For command for /? or help for
Dir command dir /? or help dir
Find command find /? or help find
Echo command echo /? or help echo
The %__AppDir__% variable is a special dynamically created variable, the content of which cannot be modified. This will always point to your appropriate \System32 directory, whether running under a 32-bit or 64-bit process. The result is that the command will not fail to run the appropriate version of Microsoft's find.exe in its correct location, eliminating a failure, should your standard environment become corrupted or modified. In addition, I used the .exe extension for find, because it is not an internal command and should your %PATHEXT% variable become corrupted or modified, the command would still work as intended.
[Edit /]
As you've further clarified that you're looking for those without files, not without files and directories, I'd offer this alternative, using the Microsoft's where.exe, windows-vista minumum:
For /F "EOL=? Delims=" %G In ('Dir /B/AD') Do #%__AppDir__%where.exe /Q "%G":*>Nul||Echo %G
If you prefer a relative path for your results, just use Echo .\%G instead
To get more information about the where command, please open a cmd window, and enter either the following command, where /?, or this one help where.
I'd like to list all .csv files in a directory and its subdirectories. It works nicely when I run this in the cmd terminal:
for /f %a in ('dir /b /s *.csv') do (echo %a)
When I put the same line of code into an (otherwise empty) text file (.cmd) and run that .cmd file, it outputs a blank line, but does not list any files.
Why does it make a difference whether I put the commands into a script or enter them directly (in one go) in the terminal?
Thinking it might be a delayed expansion issue, I also tried for /f %a in ('dir /b /s *.csv') do (echo !a!), but this doesn't list the files either.
Any ideas?
Double up the percent symbols in a batch file!
for /f %%a in ('dir /b /s *.csv') do (echo %%a)
so ive been searching for the solution to this problem for awhile now, everywhere i look everyone just says "set the compsec to point to cmd"...which is super helpful cause no one actually even says how to do that.
but when i open cmd, and type "Set" and hit ENTER, it shows ComSpec=C:\Windows\system32\cmd.exe
I checked there and sure enough, cmd.exe is in there, it works just fine. But for/f still closes before performing any operation.
How do I fix this?
#echo off
for /f "tokens=2*" %%a in ('dir /b /s findstr "Find Me Testing"') do set "AppPath=%%~b"
set "AppPath=%AppPath%"
echo %AppPath%
for /f "tokens=2*" %%a in ('dir /b /s /a-d ^| findstr "Find Me Testing"') do set "AppPath=%%~b"
set "AppPath=%AppPath%"
echo %AppPath%
pause
for /f "usebackq" %a in ('dir /b /s /a-d ^| findstr "To Be Deleted.me"') do set fileLocation=%~pa
echo %fileLocation%
pause
pause
stop
pause
wait 50
As you can see I've been testing various methods of doing what I want.
I lay good odds that your problem is with the cmd.exe autorun feature.
If you open a command session and enter cmd /?, then at about the 5th paragraph you will see the following:
If /D was NOT specified on the command line, then when CMD.EXE starts, it
looks for the following REG_SZ/REG_EXPAND_SZ registry variables, and if
either or both are present, they are executed first.
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun
and/or
HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun
I'd be willing to bet that one of those two registry settings is set to a command or script that is causing your problem. Edit your registry and remove those settings, and your problem should go away.
You can see a similar story about a user having trouble with FOR /F at https://blogs.msdn.microsoft.com/oldnewthing/20071121-00/?p=24433.
The FOR /F command executes your commands within your IN('....') clause via a new cmd.exe process, and that process will always run any autorun setting that may be present. Unfortunately it is impossible to disable this FOR /F "feature" - I think this is a horrible design flaw.
Windows pipes also use child cmd.exe processes - one for each side of the pipe. But the pipe instantiation of cmd.exe includes the /D option, so autorun is disabled. You can see this by running the following command from the command line:
echo %^cmdcmdline% | findstr "^"
On my machine it produces the following:
C:\WINDOWS\system32\cmd.exe /S /D /c" echo %cmdcmdline% "
Now do the equivalent with FOR /F (on a healthy machine)
for /f "delims=" %a in ('echo %^cmdcmdline%') do #echo %a
My machine produces:
C:\WINDOWS\system32\cmd.exe /c echo %cmdcmdline%
No /D option :(
Im trying to write a script for keep clear my desktop. I want to delete all files and directories except the shortcuts.I use Windows 10. My batch code is the following:
#echo off
COLOR 0E
cd "C:/Users/DA/Desktop"
FORFILES /S /C "if #ext!=lnk del /F /Q /S"
rd /S /Q "."
pause
exit
Maybe it is a dumb error, but Im a newbie in Windows command line. Thanks in advance.
There are several issues in your code:
You must precede the command line after the /C switch of forfiles with cmd /C, because you are using internal console commands (if, del). If you omit cmd /C, forfiles tries to find a program file named if, which does not exist.
There is no comparison operator != for the if statement. You mean not equal, so you need to state if not <expression1>==<expression2> instead.
The #ext variable expands to the file extension enclosed in quotation marks, so you need to state them around lnk also. Since the "" are in the quoted command line behind forfiles /C, you need to escape them like \" in order to establish literal " characters.
You forgot to specify what to delete at the del command.
The switches /S of forfiles and also del mean to process also items in sub-directories, but I assume you do not want that, because you want to clean up your Desktop directory.
There is the rd command, so I assume you want to remove any directories from the Desktop either. However, rd /S /Q "." tries to remove the entire Desktop directory (which will fail as your batch file changes to that directory by cd). I would put the rd command into the forfiles command line as well, because there is the possibility to check whether or not the currently iterated item is a file or a directory (forfiles features the #isdir variable for that purpose).
The cd command works only if you are running the batch file from the same drive where the Desktop directory is located (unless you provide the /D switch). I would go for the pushd command, which changes to the Desktop directory temporarily, until a popd command is there.
Instead of hard-coding the location of the Desktop directory, I would use the built-in environment variable %USERPROFILE%, which points to the user profile directory of the currently logged on user, where the Desktop directory is located in.
The exit command without the /B switch does not only end the batch file, it also terminates the command interpreter instance the batch file is running in. This does not matter when you run the batch file by double-clicking, but it does matter when you execute it within command prompt.
Here is the corrected and improved code:
#echo off
title Clean Up Desktop & rem // (this is the window title, just for fun)
color 0E
pushd "%USERPROFILE%\Desktop" || exit /B 1 & rem // (the command after `||` runs if `pushd` fails, when the dir. is not found)
rem /* Here you can see how to distinguish between files and directories;
rem files are deleted with `del`, directories are removed with `rd`.
rem The upper-case `ECHO`s are there for testing purposes only;
rem remove them as soon as you actually want to delete any items: */
forfiles /C "cmd /C if #isdir==FALSE (if /I not #ext==\"lnk\" ECHO del /F /Q #relpath) else ECHO rd /S /Q #relpath"
pause
popd & rem // (this restores the previous working directory)
exit /B & rem // (this quits the batch file only; not necessary at the end of the script)
You can try something like that :
#echo off
COLOR 0E
CD /D "%userprofile%\Desktop"
Rem To delete folders
for /f "delims=" %%a in ('Dir /b /AD ^| find /v "lnk"') do echo rd /S /Q "%%a"
pause
Rem To Delete files
for /f "delims=" %%a in ('Dir /b ^| find /v "lnk"') do echo del /F /Q /S "%%a"
pause
exit
NB: When your execution is OK, just get rid of echo command
You can use the for and if commands to accomplish this:
#echo off
COLOR 0E
cd C:/Users/DA/Desktop
for /d %x in (*) do #rd /s /q "%x"
for %i in (*) do if not %i == *.lnk del "%i"
pause
Pretty simple and works great.
Make sure that %i and %x are in "".
Let me set the stage of my issue. I have a folder (FOLDER_ABC). Within that folder, there is a folder for my application, including a unique and always changing version number (application-v1.3.4). Within that folder, there is the application (application-v1.3.4.exe) - which will also change periodically.
C:\FOLDER_ABC\application-v1.3.4\application-v1.3.4.exe
In this section below I create a directory listing of the FOLDER_ABC for any folders starting with application* and store that folder name into a file called directory.txt. I then create a perameter and store that directory into it. I'm doing it this way, versus applying the direct full path to the directory or file, since the versions will change and I don't want to hard code the batch script.
cd C:\FOLDER_ABC\
dir application* /b /ad>"C:\FOLDER_ABC\directory.txt"
set /p verdir= <C:\FOLDER_ABC\directory.txt
Here is my issue. In the section below, I'm trying to get my batch script to run the application*.exe file, and continue on with my batch file. It currently runs my application, but it hangs and doesn't continue the rest of my batch script. I'm really new to all this coding so I appreciate the help. I assume it could be something related to me not closing the FOR loop properly? How can I get it to continue on to :FINISH?
cd "C:\FOLDER_ABC\%verdir%\"
FOR /f "tokens=*" %%G IN ('dir /b *.exe') DO %%G;
:FINISH
ECHO THE END
exit
Figured it out, but didn't have enough StackOverflow credits to answer my own question. My solution is listed below. Thanks everyone. You pointed me in the right direction.
cd "C:\FOLDER_ABC\%verdir%\"
FOR %%G in (*.exe) DO START %%G
you can try:
FOR /f "delims=" %%G IN ('dir /b /a-d *.exe') DO start "" "%%~G"
I'm not sure if this is your problem, but it is possible that the ; is causing problems. You do not terminate commands with ; in batch files.
There is no need for a temporary file. Your code can be greatly simplified with FOR:
pushd c:\folder_abc
for /d %%F in (application*) do cd "%%F"
for %%F in (*.exe) do "%%F"
:FINISH
ECHO THE END
exit /b
Try using the START command:
FOR /f "tokens=*" %%G IN ('dir /b *.exe') DO START %%G;
There may be other better ways if achieving what you want, for example, if you know that the exe always has the same name as its directory, and that there will be only one such directory, you could do the following:
FOR /D %%i in (application-v*) DO START %i\%i.exe
UPDATE
From comments:
My only issue, which I just realized, is that the application folder and application name are not always identical.
In that case, you could try something like:
for /d %%i in (application-v*) do for %%j in (%%i\*.exe) do start %%j