Start *.exe from specific dir, in specific dir - batch-file

First, sorry for my English, but I try my best to explain the situation. I'm no real pro about *.bat files, but I know the basics to run exe files with it.
bat-script:
setlocal
cd "%~dp0"
start "" "%~dp0\Lang\Language.exe"
I need to start "Language.exe" inside "%~dp0" (root), where the *.bat is saved. I read many different questions/answers on stackoverflow, but none worked. The "Language.exe" is saved in "%~dp0\Lang", but it need to be run in "%~dp0" or it won't work.
The *.exe will only work from root (%~dp0), nowhere else. And there can't be any real folder structures like C:\root\Lang\Language.exe, because it have to work for others as well.
*.bat location --> root
file to start at *.bat location --> root\Lang\Language.exe
The "Language.exe" converts a language to some other with a diff-patch. I mean the *.bat starts the *.exe (also with other command variations I tried), but it says, that it can't find the files to patch. Yeah, because the so called working directory is not right (need to be "root"). But all that without moving the *.exe or anything, it should only be started in "root" from "root\Lang\Language.exe", nothing else.
EDIT:
As a workaround, I now simply move the "Language.exe", start it and move it back.
setlocal
cd "%~dp0"
move "Lang\Language.exe" "%~dp0" >nul
ECHO Starting patch...
timeout /t 1 >nul
start "" /wait "Language.exe"
move "%~dp0\Language.exe" "Lang" >nul

Set working directory
It is possible that you run into the issue discussed at In Batch file ~dp0 changes on changing directory.
I can think of 3 solutions.
Solution 1:
cd /D "%~dp0"
start "Language Patch" Lang\Language.exe
First the working directory is changed and then the EXE is called with a relative path. Parameter /D is necessary if current working directory on start is on a different drive than location of the batch file.
Solution 2:
setlocal
set "BatchPath=%~dp0"
cd /D "%BatchPath%"
start "Language Patch" "%BatchPath%Lang\Language.exe"
endlocal
The path of the folder containing the batch file is first assigned to an environment variable. This path ends with a backslash. Therefore the EXE can be called without a backslash before Lang.
Solution 3:
setlocal EnableExtensions
pushd "%~dp0"
start "Language Patch" Lang\Language.exe
popd
endlocal
push and popd are used in case of folder with batch file is not on a drive with a drive letter, but on a public network share. Read help of pushd and popd output by running in a command prompt window pushd /? and popd /? for details about those 2 commands.
Application directory used
But all those variants above do not help if Language.exe does not search for the files to patch in current working directory, but in its own application directory.
For example if Language.exe is written using Qt and uses inside the static function QCoreApplication::applicationDirPath() instead of searching for the files in current working directory, i.e. use QDir::currentPath() respectively search for the files without path and without changing working directory first.
Or if Language.exe is written using .Net and the application directory is used with one of the methods explained at How can I get the application's path in a .NET console application? instead of using current working directory.
In this case the best solution is copying Language.exe into the directory with the files to patch and delete the executable after it has terminated itself after patching all the files.
setlocal EnableExtensions
pushd "%~dp0"
copy /Y Lang\Language.exe .>nul
echo Starting patch...
Language.exe
del Language.exe
popd
endlocal

Related

Batch symbolic link creation from .txt list

I need a way to create symbolic links to multiple files in one folder, all listed in a .txt file. Filenames in the list lack the file extension. I used to do copy with the following script, and I failed to replace the copy command to symlink creation.
#echo off
chcp 65001 > nul
for /f "usebackq delims=" %%i IN ("selection_list.txt") DO (
xcopy "..\%%i.zip" "..\selection\%%i.zip*"
)
pause
Using relative paths because i wanna be able to use this in multiple folders.
Filenames in the .txt file don't include file extensions.
For instantce, let's say I wanna use this in a folder "F:\assets", i'll put my script in a folder "F:\assets\selection_script" along with the .txt file named selection_list.txt. After launching the script, it'll create a folder "F:\assets\selection" with all the files I wanted in it.
I tried replacing xcopy command with mklink /D, using this syntax example
mklink /D "C:\Link To Folder" "C:\Users\Name\Original Folder"
New script looks like this
#echo off
chcp 65001 > nul
for /f "usebackq delims=" %%i IN ("selection_list.txt") DO (
mklink /D "..\selection_links\%%i.zip*" "..\%%i.zip"
)
pause
Obviously this didn't work. Says System can't find the file selection_list.txt
I tried to manually run the command for a single named file with relative paths and it worked, so my problem is getting it to work in a function with a list. Seems to me that file extensions being added on top of filename from .txt list might be the problem, but idk how to resolve it. I tried few syntax variations I found, without success
I'm quite unexperienced with this so any help would be greatly appreciated!
Let me first explain better the task to do. There are following folders and files:
F:\assets
selection
Development & Test(!).zip
;Example Zip File.zip
selection_script
create_selection.cmd
selection_list.txt
The text file selection_list.txt contains the lines:
Development & Test(!)
;Example Zip File
Not existing file
The execution of create_selection.cmd should result in the following folders and files:
F:\assets
selection
Development & Test(!).zip
;Example Zip File.zip
selection_links
Development & Test(!).zip
;Example Zip File.zip
selection_script
create_selection.cmd
selection_list.txt
The directory entries Development & Test(!).zip and ;Example Zip File.zip in created directory selection_links are symbolic links and not copies of the two files in directory selection.
This symbolic links creation task can be done with F:\assets\selection_script\create_selection.cmd with the following command lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=*" %%G in ('%SystemRoot%\System32\chcp.com') do for %%H in (%%G) do set /A "CodePage=%%H" 2>nul
%SystemRoot%\System32\chcp.com 65001 >nul 2>&1
for %%I in ("%~dp0..\selection_links") do set "LinksFolder=%%~fI"
if not exist "%LinksFolder%\" md "%LinksFolder%" 2>nul
if not exist "%LinksFolder%\" echo ERROR: Failed to create directory: "%LinksFolder%"& goto EndBatch
pushd "%LinksFolder%"
if exist "%~dp0selection_list.txt" for /F "usebackq eol=| delims=" %%I in ("%~dp0selection_list.txt") do if exist "..\selection\%%I.zip" if not exist "%%I.zip" mklink "%%I.zip" "..\selection\%%I.zip" >nul
popd
:EndBatch
%SystemRoot%\System32\chcp.com %CodePage% >nul
endlocal
There is defined first completely the required execution environment with the first two command lines setting up a local execution environment with command echo mode turned off, command extensions enabled and delayed variable expansion disabled as required for this task.
There is next determined the currently active code page and stored in environment variable CodePage using a command line published by Compo on DosTips forum topic [Info] Saving current codepage. Then the active code page is changed to UTF-8 although not really needed for the example.
There is next determined once the full path of the folder in which the symbolic links should be created which is the folder selection_links being a subfolder of the parent folder F:\assets of the folder selection_script containing the batch script. It does not matter if this folder already exists or not on determining the fully qualified folder name.
There is next verified if the target folder exists. The folder selection_links is created on not existing with checking once again if the folder really exists now. A useful error message is output on creation of folder failed and the batch file restores the initial code page and the initial execution environment.
The target folder is made the current directory by using the command PUSHD which should not fail anymore now after verification that the target folder exists.
There are next processed the lines in the text file selection_list.txt referenced with its fully qualified file name by using %~dp0 which expands to drive and path of argument 0 which is the full path of the batch file always ending with a backlash.
Each non-empty line not starting with the character | is assigned completely one after the other to the loop variable I. The character | is not valid for a file name as explained in the Microsoft documentation about Naming Files, Paths, and Namespaces. There is verified next if there is really a ZIP archive file with that name in the folder selection and if there is no directory entry with same name in current folder selection_links.
If these two conditions are both true, MKLINK is executed to create in current directory selection_links a file symbolic link to the ZIP file in the directory selection.
Please note that a ZIP archive file is not a directory and for that reason the usage of MKLINK option /D to create a directory symbolic link cannot work ever.
Finally the initial current directory is restored using POPD and the initial code page and the initial execution environment are also restored by the batch file before it ends.
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 /? ... explains %~dp0 ... drive and path of argument 0 – the batch file path
chcp /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
mklink /?
popd /?
pushd /?
set /?
setlocal /?
See also:
Microsoft documentation about Using command redirection operators
Single line with multiple commands using Windows batch file

Test IF file exist, ELSE xcopy these two files

Morning all.
So I've been up hours trying to cobble together -a variety of replies to other posts- into my own code in order to see if I could get something usable. No-go. I'm sufficiently lost in the sauce that I've now got to ask for some help from you.
Background:
OS: Windows 10
I use the program text2folders.exe to create 20-30 new folders on a secondary drive every night.
Primarily, I have a base file "aGallery-dl.bat" that I populate each folder with using an xcopy batch file. Secondarily, from time to time I update the source file "aGallery-dl.bat" using the same xcopy and this overwrites the older target file, populating all folders with the newest "aGallery-dl.bat" (whether they need it or not). All is well.
#echo off
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
I've recently decided I want to add two new files to each folder and have expanded my xcopy to include these. All is well.
#echo off
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
Folder.jpg
a big red X
Folder2.jpg
a big yellow ! mark
When I choose to run a "aGallery-dl.bat" in a given folder (again, one of 100's), it first deletes Folder.jpg then renames Folder2.jpg to Folder.jpg. This has the effect of the red X being replaced by the yellow ! when viewing the folder in File Explorer parent folder. Secondly, it calls "gallery-dl.exe." I use going from red to yellow to let me know I've run "aGallery-dl.bat" at least once. All is well.
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\aGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
del .\Folder.jpg
If "aGallery-dl.bat" completes successfully, it finally deletes the Folder.jpg (currently yellow !), and now the representative contents of the folder (usually DeviantArt .jpg's) are visible.
Problem:
When I have to re-run my original xcopy command to update "aGallery-dl.bat" in ALL FOLDERS, the Folder.jpg and Folder2.jpg will be re-copied to all folders, defeating the purpose of deleting them once via "aGallery-dl.bat." I don't want to have to go back and re-run "aGallery-dl.bat" intermittently across 100's of folders (again, only those that have had aGallery-dl.bat run at least once). I need some type of test, that if "aGallery-dl.bat" is already present in the target folder, DO NOT xcopy Folder.jpg and Folder2.jpg aka vague example, below.
*********************************Some sort of test statement here!!!***********************
:aGallery-dlPresent
GOTO eof
:aGallery-dlNotPresent
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
GOTO eof
:eof
I had found a hopeful candidate test statement in the below (copied in its original form from what/where I read in other post), but am looking for ideas/replacements as I HAVE NO IDEA how to modify/inject/implement the below to work in the above.
If exist \\%DIR%\%Folder%\123456789.wav xcopy \\%DIR%\%Folder%\123456789.wav D:\%New Folder%\ /y
Having XCopy copy a file and not overwrite the previous one if it exists (without prompting)
Note: The below is a vague approximation of what it should all look like (barring having a correct -test statement-).
rem #echo off
*********************************Some sort of test statement here!!!***********************
:aGallery-dlPresent
GOTO eof
:aGallery-dlNotPresent
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
GOTO eof
:eof
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
The command for copying a file is COPY. It is an internal command of Windows command processor cmd.exe. XCOPY is an eXtended file and directory copying executable in directory %SystemRoot%\System32 which is deprecated since Windows Vista as there is even more powerful ROBOCOPY which is with full qualified file name %SystemRoot%\System32\robocopy.exe.
There is no need to use XCOPY or ROBOCOPY for this simple file copying task. COPY is enough on source files aGallery-dl.bat, Folder.jpgand Folder2.jpg don't have hidden attribute set and the same files in the target directories don't have read-only attribute set.
.\ references the current directory which can be any directory. Windows Explorer sets the directory of the batch file as current directory on double clicking on a batch file. But this is nearly the only method to run a batch file on which the directory of the executed batch file is set automatically as current directory (except the batch file is stored on a network resource accessed using UNC path).
There is %~dp0 to reference the path of the batch file. This path always ends with a backslash which means that no additional backslash is needed on concatenating the batch file path with a file or folder name. The usage of %~dp0 makes it possible to reference files in same directory as the executed batch file independent on which directory is the current directory on execution of the batch file.
The batch file needed for your task is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*") do (
if not exist "%%I\aGallery-dl.bat" (
copy "%~dp0Folder.jpg" "%%I\"
copy "%~dp0Folder2.jpg" "%%I\"
)
copy /Y "%~dp0aGallery-dl.bat" "%%I\"
)
endlocal
A file/folder name must be enclosed in " if containing a space or one of these characters &()[]{}^=;!'+,`~. For that reason all file/folder names are enclosed in this batch file in double quotes although inside the batch files no file/folder name contains a space or one of the characters in the list. It is important to understand on batch file writing how a command line looks like after Windows command processor processed the command line. See following topics:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
How to debug a batch file?
Windows interprets *.* like just * which means any file or folder name. For that reason it is enough to just write * and omit .*.
Please note that for /D ignores directories with hidden attribute set.
The batch file checks first for each subfolder if it does not contain the batch file aGallery-dl.bat. In this case it copies the two files Folder.jpg and Folder2.jpg from directory of executed batch file to current subdirectory of U:\11Web\gallery-dl\deviantart.
Then the batch file aGallery-dl.bat is copied from directory of executed batch file to to current subdirectory of U:\11Web\gallery-dl\deviantart independent on its existence in the destination directory.
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 /? ... explains %~dp0 ... drive and path of argument 0 ... full batch file path.
cmd /? ... outputs the help of Windows command processor executing a batch file.
copy /?
echo /?
endlocal /?
for /?
if /?
setlocal /?
See also the chapters Issue 6 and Issue 7 in this answer why using setlocal EnableExtensions DisableDelayedExpansion and endlocal although not necessary by default and why using I instead of a as loop variable although a would work here, too.

Recursive rename isn't working at all in batch

So I have been searching in other topics how to rename files and folders in a .bat in a recursive way but it isn't working at all.
My code is:
# echo off
setlocal enabledelayedexpansion
set /p rut="Introduce folder: "
FOR /D /R %%x in ("%rut%"\*) DO (
cd %rut%
echo %cd%
pause
ren .\* "a"
)
exit
But this only renames the files that are on the first folder and not in the rest. Forfile won't work at all with the variables.
What I want to get is how I could rename everything inside the main folder (including subfolders) whatever it is, be it files or folders as "a" to solve the Windows problem of having routes way too long when trying to delete a full structure, that is why I can't use the ".txt" ".whatever" solution.
A powershell solution would be valid too!
Thank you very much
Edit I added a random to see if it was the name that was conflicting but no, it is still not working:
ren .\* "a%RANDOM%"
And renaming them from cmd works the same way, I mean, if I write ren "folder" "whatever" it will change but in the script doesn't work with "*"

Renaming Multiple Files in Subdirectories

Long story short, I accidentally wiped my HDD the other day while trying to install a new SSD. I used a great program to undelete my partition; however, all the files were given an .efs extension. I am currently using:
:begin
RENAME *.extension.efs *.
I have tons of lines written for each file type, and this command works flawlessly. The only problem is that I have to manually paste this .bat into every folder and execute it in order for it to work.
Is there a way I can make it so when I run this .bat, it will go through all folders and subdirectories from a central directory? I'm anal about organization so all my music, albums, videos, TV shows, etc., are all in separate folders and it would take quite some time for me to run my original .bat from each.
Any help is appreciated!!
for /r /d %n in (.) do pushd "%n"&call "fullpathtoyourniftybatchfile"&popd
from the prompt will traverse the entire tree from wherever your current directory is.
You could also place your batch into any directory on your path and execute
for /r /d %n in (.) do pushd "%n"&call "yourniftybatchfilename"&popd
since windows searches the path for any executable it can't find in the current directory.
Here is a script that will rename files with extension efs in the current directory and all subfolders starting at the current directory. %%i is replaced by the full path to a folder or subfolders. Line 2 is needed because the for loop only does folders and subfolders.
#echo off
ren *.efs *.
for /f "tokens=* usebackq" %%i in (`dir/b/ad/s`) do (
cd %%i
ren *.efs *.
)

Why does this Windows batch file behave differently when operating on a local vs. network path?

I am executing a Windows batch file in Jenkins. Part of the script looks for files matching *.cover.xml and runs an external program on each of them. The relevant part of that batch file looks like this
SETLOCAL ENABLEDELAYEDEXPANSION
SET project_path=\\home\Sonar\8.1
PUSHD %project_path%
FOR /R %%i IN (*.cover.xml) do ncxc.exe %%i
POPD
When I set the project_path to a local path, like D:\MyProj\, it works perfectly. When I use a UNC path, like above, there's a problem. The first time it runs, it passes. Every time after that, it fails!
'ncxc.exe' is not recognized as an internal or external command, operable program or batch file.
I ran DIR at the end of the script and the directory is empty! The Jenkins service is running as domain user and the copy command works with network resources. And PUSHD mounts the UNC path to a drive letter.
EDIT - the entire batch file which also fails the same way
set deployment_path=d:\deployment\
SETLOCAL ENABLEDELAYEDEXPANSION
set project_path=Z:\8.1\
pushd %project_path%
set some_path=%CD%
copy %deployment_path%\sppg.exe %CD%\sppg.exe /y
copy %deployment_path%\sonar_main.bat %CD%\sonar_main.bat /y
copy %deployment_path%\utils_all.bat %CD%\Utils\utils.all.bat /y
copy %deployment_path%\dunit2surefire.xsl %CD%\HCPC\dunit2surefire.xsl /y
copy %deployment_path%\xslt2xml.exe %CD%\HPC\xslt2xml.exe /y
copy %deployment_path%\sonar_delphi_all.bat %CD%\HPC\sonar_delphi_all.bat /y
copy %deployment_path%\xslt.bat %CD%\HCPC\Client\xslt.bat /y
copy %deployment_path%\xslt.bat %CD%\HCPC\Server\xslt.bat /y
copy %deployment_path%\ncxc.exe %CD%\ncxc.exe /y
copy %deployment_path%\ncover-converter.bat %CD%\ncover-converter.bat /y
ncxc.exe %CD%
popd
pushd %project_path%
sppg.exe "%CD%" ./Output_AutomatedBuild/TestsResults/Coverage/*.cover.xml
dir Z:
sonar_main.bat
popd
CMD can't start from a UNC path without registry hack.
Your problem seems a little strange. I would recommend to use just the UNC paths for copying.
set deployment_path=d:\deployment\
SETLOCAL ENABLEDELAYEDEXPANSION
set project_path=\\server\share
copy %deployment_path%\sppg.exe %project_path%\sppg.exe /y
this is no problem at all. try it. I also recommend to never use %cd% because it can't securly rely what is its content.
and for the exe file: just give it's full qualified path.
%project_path%\ncxc.exe ...

Resources