How to source a Windows batch script - cmd

For example, I have a simple batch script get_path.bat
#echo off
echo C:\Software\dt
Also, I have another simple batch script switch_dir.bat
#echo off
get_path.bat > target.tmp
set /p TARGET=<target.tmp
cd %TARGET%
Now, what I want to accomplish is that when I invoke in cmd.exe the batch file switch_dir.bat, my current working directory changes to C:\Software\dt.
As of now, the scripts work but they run in a process spawned from cmd.exe so my current working directory stays the same. What is missing? Basically, we need Unix-like source or . here.

Well, there are many possible solutions:
Start your script with cmd /c:
All you have to write in cmd is:
cmd /c switch_dir.bat
Using popd/pushd in your batch file:
In your switch_dir.bat add:
#echo off
pushd dir\you\want\to\remain\
get_path.bat > target.tmp
set /p TARGET=<target.tmp
cd %TARGET%
rem [code...]
popd
An additional note: A better way to find directory specified in get_path.bat is to use a for /f loop like this:
#echo off
pushd dir\you\want\to\remain\
for /f "delims=" %%A IN ('get_path.bat') do set TARGET=%%A
cd %TARGET%
rem [code...]
popd

Related

To run a windows command over multiple files on the same time

I want to trigger a windows command over multiple files inside a directory at the same time. 'FOR' loop and other recursive methods are triggering the commands one after another. I need an alternative that can run the same command on all files at the same time. The present code I have is
#echo off
call :scan
goto :eof
:scan
for %%f in (*.txt) do *mycommand* -i %%f
for /D %%d in (*) do (
cd %%d
call :scan
cd ..
)
exit /b
The easiest way to have slow tasks running in parallel on Windows is by using the start command and calling another batch file, e.g.:
scan.bat
#echo off
echo Processing %1
dir %1
exit
main.bat
for %%f in (*.txt) do start scan.bat %%f
This will create a new window for each scan.bat instance. If you want to use the current window, use start /b scan.bat.
The exit command at the end of scan.bat is important so that the command processor exists (so that the window is closed).
In case you want to limit the number of tasks running in parallel, you should use something more powerful like gnu make (which can be used on Windows with cygwin or mingw; see Limiting the number of spawned processes in batch script for a solution using batch files (from #LotPings).

cmd: run exe from a folder with dynamic name

I have an exe file, say, C:\Programs\tools\4.0.97869\program.exe
This, obviously, version number may vary, but I'm totally sure that it will always be 4.0.something
I can execute some command from batch file, specifying path to that exe like this:
"C:\Programs\tools\4.0.97869\program.exe" /option:Key somevalue
Which works perfectly fine. However, I would like to place a wildcard here, for example like this:
C:\Programs\tools\4.0.*\program.exe
Since I can perfectly navigate like this using cd
I do not want to specify that exe in Path
I do not want to cd to that directory and call program.exe from there
It there a way to specify first matching directory which has a
necessary file to execute in one line?
Thanks.
Here is a solution that uses a PowerShell script:
$pathPattern = 'C:\Programs\tools\4.0.*\program.exe'
if(!(Test-Path $pathPattern)){
throw "Could not find a single executable"
}
$paths = Get-Item -Path $pathPattern
Invoke-Expression $paths[0]
A PowerShell solution would be a better idea. If only cmd.exe can be used, the following might work. It is not a one-liner. Store this in a .bat file and CALL it. It works by running the first "program.exe" it can find. It tries to get the most recent one by ordering the directory search as most recent first.
SETLOCAL ENABLEDELAYEDEXPANSION
SET EXITCODE=0
SET "EXEWILD=C:\Programs\tools\4.0.*"
FOR /F %%d IN ("%EXEWILD%") DO (SET "EXEBASE=%%~dpd")
IF NOT EXIST "%EXEWILD%" (
ECHO ERROR: Tool directory "%EXEWILD%" does not exist.
SET EXITCODE=4
GOTO TheEnd
)
FOR /F "usebackq tokens=*" %%d IN (`DIR /B /O-D "%EXEWILD%"`) DO (
IF EXIST "%EXEBASE%\%%~d\program.exe" (
"%EXEBASE%%%~d\program.exe" %*
SET EXITCODE=!ERRORLEVEL!
GOTO TheEnd
) ELSE (
ECHO WARNING: program.exe not found in "%EXEBASE%\%%~d"
)
)
:TheEnd
EXIT /B %EXITCODE%

How to process 2 FOR loops after each other in batch?

My problem is that two FOR loops are working separately, but don't want to work one after another.
The goal is:
The first loop creates XML files and only when the creation has already been done the second loop starts and counts the size of created XML files and writes it into .txt file.
#echo off
Setlocal EnableDelayedExpansion
for /f %%a in ('dir /b /s C:\Users\NekhayenkoO\test\') do (
echo Verarbeite %%~na
jhove -m PDF-hul -h xml -o C:\Users\NekhayenkoO\outputxml\%%~na.xml %%a
)
for /f %%i in ('dir /b /s C:\Users\NekhayenkoO\outputxml\') do (
echo %%~ni %%~zi >> C:\Users\NekhayenkoO\outputxml\size.txt
)
pause
This question can be answered easily when knowing what jhove is.
So I searched in world wide web for jhove, found very quickly the homepage JHOVE | JSTOR/Harvard Object Validation Environment and downloaded also jhove-1_11.zip from SourceForge project page of JHOVE.
All this was done by me to find out that jhove is a Java application which is executed on Linux and perhaps also on Mac using the shell script jhove and on Windows the batch file jhove.bat for making it easier to use by users.
So Windows command interpreter searches in current directory and next in all directories specified in environment variable PATH for a file matching the file name pattern jhove.* having a file extension listed in environment variable PATHEXT because jhove.bat is specified without file extension and without path in the batch file.
But the execution of a batch file from within a batch file without usage of command CALL results in script execution of current batch file being continued in the other executed batch file without ever returning back to the current batch file.
For that reason Windows command interpreter runs into jhove.bat on first file found in directory C:\Users\NekhayenkoO\test and never comes back.
This behavior can be easily watched by using two simple batch files stored for example in C:\Temp.
Test1.bat:
#echo off
cd /D "%~dp0"
for %%I in (*.bat) do Test2.bat "%%I"
echo %~n0: Leaving %~f0
Test2.bat:
#echo %~n0: Arguments are: %*
#echo %~n0: Leaving %~f0
On running from within a command prompt window C:\Temp\Test1.bat the output is:
Test2: Arguments are: "Test1.bat"
Test2: Leaving C:\Temp\Test2.bat
The processing of Test1.bat was continued on Test2.bat without coming back to Test1.bat.
Now Test1.bat is modified to by inserting command CALL after do.
Test1.bat:
#echo off
cd /D "%~dp0"
for %%I in (*.bat) do call Test2.bat "%%I"
echo Leaving %~f0
The output on running Test1.bat from within command prompt window is now:
Test2: Arguments are: "Test1.bat"
Test2: Leaving C:\Temp\Test2.bat
Test2: Arguments are: "Test2.bat"
Test2: Leaving C:\Temp\Test2.bat
Test1: Leaving C:\Temp\Test1.bat
Batch file Test1.bat calls now batch file Test2.bat and therefore the FOR loop is really executed on all *.bat files found in directory of the two batch files.
Therefore the solution is using command CALL as suggested already by Squashman:
#echo off
setlocal EnableDelayedExpansion
for /f %%a in ('dir /b /s "%USERPROFILE%\test\" 2^>nul') do (
echo Verarbeite %%~na
call jhove.bat -m PDF-hul -h xml -o "%USERPROFILE%\outputxml\%%~na.xml" "%%a"
)
for /f %%i in ('dir /b /s "%USERPROFILE%\outputxml\" 2^>nul') do (
echo %%~ni %%~zi>>"%USERPROFILE%\outputxml\size.txt"
)
pause
endlocal
A reference to environment variable USERPROFILE is used instead of C:\Users\NekhayenkoO.
All file names are enclosed in double quotes in case of any file found in the directory contains a space character or any other special character which requires enclosing in double quotes.
And last 2>nul is added which redirects the error message output to handle STDERR by command DIR on not finding any file to device NUL to suppress it. The redirection operator > must be escaped here with ^ to be interpreted on execution of command DIR and not as wrong placed redirection operator on parsing already the command FOR.
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 /?
cd /?
dir /?
echo /?
for /?
And read also the Microsoft article Using command redirection operators.
You need to use the START command with the /WAIT flag when you launch an external application.
I believe it would look something like this:
START /WAIT jhove -m PDF-hul -h xml -o C:\Users\NekhayenkoO\outputxml\%%~na.xml %%a
That should cause the batch file to pause and wait for the external application to finish before proceeding.

CD into path from shell script

I have written a program found here Project. Its purpose is to make command line navigation quicker by allowing the user to create variables and run custom commands. One thing it allows you to do is cd into the path of a stored variable. I achieve this by running the program using the following bat script:
#ECHO OFF
set curDir = %cd%
pushd %~dp0
set VAR = ""
FOR /F "delims=" %%I IN ('main.exe %curDir % %1 %2 %3 %4 %5 %6 %7 %8 %9') do set VAR=%%I & ECHO %%I
type log.txt
popd
%VAR% 2>nul
If the program returns the 'cd' command and it is run from the bat script which alters the users current directory outside the context of the program and the bat script.
I want to port this to Linux but cant seem to figure out how to write a shell script that produces the same behavior. Is this possible?
Yes, it is possible. Just call the script as . myScript (note the space). This allows the script to mess with the running users environment. I have a similar script that I used for moving around our svn repos.

Batch script to execute some commands in each sub-folder

I need to write a script to work in Windows, that when executed will run a command in some of sub-directories, but unfortunately I have never done anything in batch, and I don't know where to start.
With the example structure of folders:
\root
\one
\two
\three
\four
I want the script to enter the specified folders (e.g. only 'one' and 'four') and then run some command inside every child directories of that folders.
If you could provide any help, maybe some basic tutorial or just names of the commands I will need, I would be very grateful.
You can tell the batch to iterate directories:
for /d %i in (C:\temp\*) do ( cd "%i" & *enter your command here* )
Use a percent sign when run directly on the command line, two when run from a batch
In a batch this would look something like this:
#echo off
set back=%cd%
for /d %%i in (C:\temp\*) do (
cd "%%i"
echo current directory:
cd
pause
)
cd %back%
Put the commands you need in the lines between ( and ).
If you replace C:\temp\ with %1 you can tell the batch to take the value of the directory from the first parameter when you call it.
Depending of the amount of directories you then either call the batch for each directory or read them from a list:
for /f %i in (paths.lst) do call yourbatch %i
The paths.lstwill look like this:
C:\
D:\
Y:\
C:\foo
All of this is written from memory, so you might need to add some quotations marks ;-)
Please note that this will only process the first level of directories, that means no child folders of a selected child folder.
You should take a look at this. The command you are looking for is FOR /R. Looks something like this:
FOR /R "C:\SomePath\" %%F IN (.) DO (
some command
)
I like answer of Marged that has been defined as BEST answer (I vote up), but this answer has a big inconvenience.
When DOS command between ( and ) contains some errors, the error message returned by DOS is not very explicit.
For information, this message is
) was unexpected at this time.
To avoid this situation, I propose the following solution :
#echo off
pushd .
for /d %%i in (.\WorkingTime\*.txt) do call :$DoSomething "%%i"
popd
pause
exit /B
::**************************************************
:$DoSomething
::**************************************************
echo current directory: %1
cd %1
echo current directory: %cd%
cd ..
exit /B
The FOR loop call $DoSomething "method" for each directory found passing DIR-NAME has a parameter. Caution: doublequote are passed to %1 parameter in $DoSomething method.
The exit /B command is used to indicate END of method and not END of script.
The result on my PC where I have 2 folders in c:\Temp folder is
D:\#Atos\Prestations>call test.bat
current directory: ".\New folder"
current directory: D:\#Atos\Prestations\New folder
current directory: ".\WorkingTime"
current directory: D:\#Atos\Prestations\WorkingTime
Press any key to continue . . .
Caution: in Margeds answer, usage of cd "%%i" is incorrect when folder is relative (folder with . or ..).
Why, because the script goto first folder and when it is in first folder it request to goto second folder FROM first folder !
On Windows 10 and later, it should be like this:
#echo off
for /D %%G in ("C:\MyFolderToLookIn\*") DO (
echo %%~nxG
)
This will show the name of each folder in "C:\MyFolderToLookIn". Double quotes are required.
If you want to show full path of the folder, change echo %%~nxG with echo %%G

Resources