Batch script to read input text file and build output command - batch-file

I have a batch file that will run csc using a file as input. I want to modify it to read references from a file, and add them to the line that is executed when the script runs.
I've tried a few different things but can't seem to get it work. The references are added with /r: and then each reference path has semi-colon as a separator.
Ideally, I'd like to just have a reference on a new line in the text file. The ref.txt file is in the same directory as the input file, and I'm not sure if it was looking in this directory or not. I also want to make it attempt to run without the ref.txt file, so I added the exists line to do this. I've never used batch scripting before, so maybe someone else knows how to do this better than me. I think that the first line needs to match the start line, which I tried to do in other attempts, but it wasn't working.
The script works in Notepad++, and was from this answer. I think now that the run command also needs to be modified.
This is the run command in Notepad++:
C:\bin\csc.bat "$(CURRENT_DIRECTORY)\$(NAME_PART).exe" "$(FULL_CURRENT_PATH)"
This is the version from that answer:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc /out:%1 %2
#echo off
if errorlevel 1 (
pause
exit
)
start %1 %1
This is an attempt to use references:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc /out:%1 %2
#echo off
if errorlevel 1 (
pause
exit
)
if not exist ref.txt GOTO :write
set a = /r:
set refs = type ref.txt
start %1 %a% and %refs% and %1
exit
write
start %1 %1
The refs.txt file contains file paths like this:
C:\windows\some_path\some_file.dll;C:\windows\some_path\another_file.dll;
An example command from Microsoft is:
csc /t:exe /r:MyCodeLibrary.dll;NewLib.dll *.cs

IIUR you are trying to apply the refs to the compiled exe not to csc itself.
You need to adapt the path to the ref.txt file
:: Q:\Test\2019\01\25\SO_54360791.cmd
#echo off & Setlocal EnableDelayedExpansion
Set CSC="C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
Set Ref=".\ref.txt"
if exist %Ref% (
<%Ref% Set /p "refs="
set "refs=/r:!refs!"
) else set "refs="
%CSC% %refs% /out:%1 %2
if errorlevel 1 (
pause
exit
)
sample (echoed) output
> SO_54360791.cmd new.exe source.cs
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" /r:C:\windows\some_path\some_file.dll;C:\windows\some_path\another_file.dll; /out:new.exe source.cs
I'm not sure if the trailing semicolon in your sample ref.txt will work.
EDIT: Variant with ref.txt file containing quoted pathes with trailing semiclon
:: Q:\Test\2019\01\25\SO_54360791.cmd
#echo off & Setlocal EnableDelayedExpansion
Set CSC="C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
Set Ref=".\ref.txt"
Set "refs="
if not exist %Ref% goto :cont
set "refs=/r:"
for /f "usebackq delims=" %%A in (%Ref%) Do set "refs=!refs!%%A"
:cont
echo %CSC% %refs% /out:%1 %2
if errorlevel 1 (
pause
exit
)
goto :Eof
sample (echoed) output
> SO_54360791.cmd new.exe source.cs
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" /r:"C:\windows\some_path\some_file.dll";"C:\windows\some_path\another_file.dll"; /out:new.exe source.cs

Related

Am I the only one who have this problem: While running something like .bat, the "X:\..\..path" often becomes ""X:\..\path and producing errors?

While running something like .bat, the "X:\..\..path" often becomes ""X:\..\path and producing errors. For example, I was installing apktool, then it just appeared this:
'""C:\Program' is not recognized as an internal or external command,
operable program or batch file.
I then copy the command and put one of the double quote to the end, which is like this: "C:\Program"
And everything just went smoothly, installation was successful. Then I tried to decode an apk, and the exactly same problem occurred: '""C:\Program' is not recognized as an internal or external command, operable program or batch file. This time I have no idea how to fix it, it's not like the .bat now, I cannot get the #echo on and copy the last command and edit it. So I am here to ask: If I am the only one who met this? Any way to fix this? Thank you.
My command:
apktool d test.apk
Image of running a decode command : 1
apktool.bat content:
#echo off
setlocal
set BASENAME=apktool_
chcp 65001 2>nul >nul
set java_exe=java.exe
if defined JAVA_HOME (
set java_exe="%JAVA_HOME%\bin\java.exe"
)
rem Find the highest version .jar available in the same directory as the script
setlocal EnableDelayedExpansion
pushd "%~dp0"
if exist apktool.jar (
set BASENAME=apktool
goto skipversioned
)
set max=0
for /f "tokens=1* delims=-_.0" %%A in ('dir /b /a-d %BASENAME%*.jar') do if %%~B gtr !max! set max=%%~nB
:skipversioned
popd
setlocal DisableDelayedExpansion
rem Find out if the commandline is a parameterless .jar or directory, for fast unpack/repack
if "%~1"=="" goto load
if not "%~2"=="" goto load
set ATTR=%~a1
if "%ATTR:~0,1%"=="d" (
rem Directory, rebuild
set fastCommand=b
)
if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
rem APK file, unpack
set fastCommand=d
)
:load
"%java_exe%" -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
rem Pause when ran non interactively
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign a terminal \, Space or " - build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.
set java_exe="%JAVA_HOME%\bin\java.exe"
Should be
set "java_exe=%JAVA_HOME%\bin\java.exe"
(apply this principle throughout your code)
Then, if you require " anywhere, insert it where it's needed - don't try to include it as part of a variable's value.
This should clean up at least some of your problems.

How to handle space in UNC path in a batch file?

The Windows server my team uses recently got upgraded. A batch file, which used to work fine, is now not working due to spacing in a directory path. I believe the robocopy command is failing.
How can I get the command to work properly and recognize the space in the directory path correctly?
Batch file code:
#ECHO OFF
:start
rem GOTO end
if exist %1*_desc.xml (
del %1*_desc.xml
goto final
)
:final
rem Rename files with -en-us
setlocal enabledelayedexpansion
set "Pattern=-en-us"
set "Replace="
for %%# in (%1*.*) do (
set "File=%%~nx#"
ren "%%#" "!_File:%Pattern%=%Replace%!"
)
:end
copy %1*.* %2*.*
::robocopy "%1" "%2" *.*
Command being executed:
D:\scripts\Maintenance\COGCleanup.bat "\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\"
Output error message:
\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\*.*
Access is denied.
0 file(s) copied.
NOTE: In the above error message, the first part of the directory (before access is denied) is underlined and in blue. I can't replicate it here. The space after Application is what's causing the issue I believe.
If this is the command you used:
D:\scripts\Maintenance\COGCleanup.bat "\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\"
%1 is "\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\" (quotes included).
%1*.* is "\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\"*.*
"%1" is ""\\nycb\corp$\group\IT\IT-NY\Application Development\CognosTest\"" and will be parsed as 2 parameters \\nycb\corp$\group\IT\IT-NY\Application and Development\CognosTest\.
You can fix is by using "%~1" (with quotes).
%~1 is %1 without quotes, if there are quotes. No matter if %1 is "foo" or foo, %~1 is always foo, and "%~1" is always "foo"

Batch %1 get path with whitespace

I have set up a batch file to be default to open .txt files. In an earlier question I found out that %1 gives me the path of the file which was actually calling the batch file. The Problem is: if the file name contains white space, it gets interpreted as multiple parameters.
Example:
opening file "C:\Users\Desktop\space true.txt"
%1 gives:"C:\Users\Desktop\space" and then %2 gives: "true.txt"
How could I get just the full file path with the name and white space without trying to do a loop to attempt to get the full path by combining %1%2%3%4...
UPDATE-----------------------
Sorry there was a miss communication. The code below is working. The trick was to put "%*" instead of "%1"
here the code:
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
I do the whole changing the path, because the file which I double click and the the the batch file are in different directories. I had to change it to this.
UPDATE 2 --------------------------
The solution which worked best for me was from this fine gentlemen dbenham.
#echo off
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
The only complain I have is, that there is a case, where %* does not return the path with quotes. So I am searching for a final solution. Something like this "%~*" But this doesn't work.
Thanks in advance
The following is not quite correct - I thought the file associations would put quotes around the file name like drag and drop does. But I was mistaken
This line is the source of your problem:
set var= "%*"
When files are dragged onto your batch script, or if a text file is double clicked, any file name(s) containing space will automatically be enclosed within quotes.
When you add your own additional quotes, it defeats the purpose of the quotes - the space is no longer quoted.
For example, a string like "name with space.txt" is treated as a single arg, but with added quotes, ""name with space.txt"" becomes three arguments.
There is no need for your var variable. You can use %* directly in your START command.
#echo on
pushd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" %*
pause
I'm not sure the above works properly if multiple files are passed. I suspect you may want the following:
#echo on
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
pause
There is one potential problem. Windows has a bug in that file names containing & are not automatically quoted as they should. See "Droplet" batch script - filenames containing ampersands for more info.
EDIT - The following should work
OK, I did some tests and I believe your best bet is to modify the command associated with .txt files.
I tested association changes via the command line. This must be done via an elevated command prompt with admin rights. On my machine I go to the Start menu, click on "All Programs", click on "Accessories" folder, right click "Command Prompt", and select "Run as administrator", then click "Yes" to allow the program to make changes to the system.
The following command will show which file type needs to be modified
assoc .txt
On my machine it reports .txt=txtfile, so txtfile is what must be modified using FTYPE.
I believe the following should work for you:
ftype txtfile="C:\pathToYourScrpt\yourScript.bat" "%1"
Obviously you would need to fix the path to your batch script :-)
Once you have made the change, the filename will automatically be quoted every time your script is invoked via a file association.
Your batch script can then look like the following, and it should work no matter how it is invoked (excepting drag and drop with file name containing & but no space):
#echo off
pushd "C:\Users\MyText Editor"
for %%F in (%*) do start javaw -jar "MyTextEditor.jar" %%F
It seems to me you should be able to eliminate the batch script and configure FTYPE TXTFILE to open your java editor directly. I should think something like the following:
ftype txtfile="c:\pathToJava\javaw.exe" -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%1"
When calling your batch file, you must enclose your parameter in quotes if there is spaces in it.
E.g.: Batch.cmd "C:\Users\Desktop\space true.txt"
Eric
%*
Here's a list of characters.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
Your problem is really that the syntax of your set command is wrong. In a batch
file, a set command looks like this:
set "var=%1"
That will give you your variable exactly as received. If the user quoted it,
then the variable's value will have quotes around it. To remove the quotes,
you'd put a ~ in front of the number:
set "var=%~1"
Notice how the quotes go around the entire assignment, and not just around the
value you are assigning. It is not set var="%1".
If you use set var= "%*", you haven't really fixed the fundamental problem
that your syntax is wrong. Plus, often you really do want %1 and not the
entire command line.
Here is an example script to test various quoting behaviors:
#echo off
set var="%*"
echo 1. var="%%*" --^> [%var%] (wrong)
set "var=%*"
echo 2. "var=%%*" --^> [%var%]
set "var=%1"
echo 3. "var=%%1" --^> [%var%]
set "var=%~1"
echo 4. "var=%%~1" --^> [%var%]
set "var=%~2"
echo 5. "var=%%~2" --^> [%var%]
set "var=%~3"
echo 6. "var=%%~3" --^> [%var%]
And here is the output of that script. Note how arg1, arg2, and arg3 are all
quoted:
C:\batch> all_args.cmd "arg 1" "this is arg 2" "arg 3"
1. var="%*" --> [""arg 1" "this is arg 2" "arg 3""] (wrong)
2. "var=%*" --> ["arg 1" "this is arg 2" "arg 3"]
3. "var=%1" --> ["arg 1"]
4. "var=%~1" --> [arg 1]
5. "var=%~2" --> [this is arg 2]
6. "var=%~3" --> [arg 3]
You can see that numbers 4, 5, and 6 correctly pulled out their quoted arguments
and saved the value into var. You typically want to save the argument without quotes, and then quote it when you use it in your script. In other words, your script should look like this:
#echo on
set "var=%~1"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar" "%var%"
pause
#echo on
set var= "%*"
c:
cd "C:\Users\MyText Editor"
start javaw -jar "MyTextEditor.jar"%var%
pause
Becomes removing redundant commands
start "" javaw -jar "C:\Users\MyText Editor\MyTextEditor.jar" "%*"
pause
Echo is already on unless turned off by you.
We don't put things into variables for no reason, and it's already in %*. It just makes convoluted code and removes meaning from the name of the variable.
When programming (unlike typing) we don't change paths (and cd /d C:\Users\MyText Editor does drive and folder anyway).
We specify full path on the command line. This makes your meaning quite clear.
The main problem was there was no space between .jar and %var% and start command the first quotes on the line are assumed to the CMD's window title. I would code the path to javaw and not use start. Start is asking the Windows' graphical shell to start the file, not CMD.
Here's a batch file that starts vbs files. I don't specify path to cscript as it's a Windows' command.
It's complexity is to make use fairly idiot proof and easy for others.
#echo off
Rem Make sure filter.vbs exists
set filter=
set filterpath=
Call :FindFilter filter.vbs
Rem Add filter.bat to the path if not in there, setx fails if it's already there
setx path %~dp0;%path% 1>nul 2>nul
Rem Test for some command line parameters
If not "%1"=="" goto main
echo.
echo -------------------------------------------------------------------------------
echo.
echo Filter.bat
echo ==========
echo.
echo The Filter program is a vbs file for searching, replacing, extracting, and
echo trimming console output and text files.
echo.
echo Filter.bat makes Filter.vbs easily usable from the command line. It
echo controls unicode/ansi support and debugging.
echo.
echo Type Filter Help or Filter HTMLHelp for more information.
echo.
cscript //nologo "%filter%" menu
Goto :EOF
:Main
echo %date% %time% %~n0 %* >>"%~dp0\FilterHistory.txt"
rem echo Batch file ran
rem echo %*
Rem /ud Unicode and Debug
If %1==/ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==/u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem /d Ansi Debug
If %1==/d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem -ud Unicode and Debug
If %1==-ud FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u //x %%j&Goto :EOF
Rem /u Unicode
If %1==-u FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //u %%j&Goto :EOF
Rem -d Ansi Debug
If %1==-d FOR /F "tokens=1*" %%i IN ("%*") DO cscript "%filter%
" //nologo //x %%j&Goto :EOF
Rem ANSI
cscript "%filter%
" //nologo %*&Goto :EOF
Goto :EOF
:FindFilter
If Exist "%~dpn0.vbs" set filter=%~dpn0.vbs&set filterpath=%~dp0&goto :EOF
echo find filter 1
If Not "%~dpnx$PATH:1" == "" set filter=%~dpnx1&set filterpath=%~dp1&goto :EOF
echo find filter 2
If Exist "%temp%\filter.vbs" set filter=%temp%\filter.vbs&set filterpath=%temp%&goto :EOF
copy "%~dpnx0" "%~dpn0.bak"
if not errorlevel 1 (
echo creating "%~dpn0.vbs"
goto :EOF
)
copy "%~dpnx0" "%temp%\filter.bak"
echo Error %errorlevel%
if not errorlevel 1 (
echo creating "%temp%\filter.bak"
Goto :EOF
)
Goto :EOF

How to choose one of multiple actions based on file extension, in batch

I'm an amateur on the usage of the FOR command. I need a batch file that will run one of 5 file conversion tools based on a file's extension. I want to drop a file onto the batch file icon and have it converted.
Since my list is huge, I can't use nested IF's.
What I've tried so far:
#ECHO OFF
SET cadfile=.dwg .dxf .dwf
SET gsfile=.ps .eps .epi .epsp
SET xxxxxx=.xx .xx and goes on
FOR %%~x1 in (%cadfile%) do (
Do some action
FOR %%~x1 in (%gsfile%) do (
Do some other action
)
)
The %%~x1 variable is used for file extension of file, which dragged and dropped over the batch file.
(edited to make more clear)
FOR %%a in (%cadfile%) do (
if /i "%~x1"=="%%a" some_action "%~1"
)
... and follow the bouncing ball for the rest of the utilities/lists
I think this will work for you. It looks through all your groups of extensions in a single For loop and when the matching extension is found, calls a label where you can do the conversion and any related tasks. You'll need to finish the "groupN" variables and labels.
#echo off
SETLOCAL EnableDelayedExpansion
set file="%1"
set ext=%~x1
:: Set the 5 groups of extensions that have different converters
set group1=.dwg, .dxf, .dwf
set group2=.ps, .eps, .epi, .epsp
For %%A in (1 2 3 4 5) do (
set groupnum=group%%A
call set thisgroup=%%!groupnum!%%
:: Look for extension in this group
echo.!thisgroup!|findstr /i /C:"%ext%" >nul 2>&1
if not errorlevel 1 call :group%%A
:: else go loop next group
)
echo Extension not found in any group &pause &goto end
:group1
echo group1 file to convert is %file%
goto end
:group2
echo group2 file to convert is %file%
goto end
:end
pause
exit
The following method allows you to easily add and modify your list of extensions/applications. Please note that you just need to edit the values placed inside the first FOR command; the rest of the program is the solution you don't need to care of...
#echo off
setlocal EnableDelayedExpansion
rem Define the list of extensions per application:
rem (this is the only part that you must edit)
for %%a in ("cadfile=.dwg .dxf .dwf"
"gsfile=.ps .eps .epi .epsp"
"xxxxxx=.xx .xx1 .xx2") do (
rem The rest of the code is commented just to be clear,
rem but you may omit the reading of this part if you wish
rem Separate application from its extensions
rem and create a vector called "ext" with an element for each pair
for /F "tokens=1,2 delims==" %%b in (%%a) do (
rem For example: %%b=cadfile, %%c=.dwg .dxf .dwf
for %%d in (%%c) do set "ext[%%d]=%%b"
rem For example: set "ext[.dwg]=cadfile", set "ext[.dxf]=cadfile", set "ext[.dwf]=cadfile"
rem In the next line: set "ext[.ps]=gsfile", set "ext[.eps]=gsfile", etc...
)
)
rem Now process the extension of the file given in the parameter:
if defined ext[%~x1] goto !ext[%~x1]!
echo There is no registered conversion tool for %~x1 extension
goto :EOF
:cadfile
echo Execute cadfile on %1 file
rem cadfile %1
goto :EOF
:gsfile
echo Execute gsfile on %1 file
rem gsfile %1
goto :EOF
etc...
If each conversion tool is executed in the same way and don't require additional parameters (just the filename), then you may omit the individual sections and directly execute the conversion tools this way:
if defined ext[%~x1] !ext[%~x1]! %1
For further explanations on array concept, see this post.

Temporarily set file associations

I have a portable development tool that I want to use on other PCs. I'd like to set a file association so that clicking a file opens the tool. Then, when I'm finished, I want to undo or reset the file association on that PC.
Is there a way to do this? Possibly from a batch file?
Well, you can use the ftype and assoc commands to create or delete file type associations:
ASSOC .foo=FooFile
FTYPE FooFile=X:\Foo\foo.exe %1 %*
You can delete them later with
FTYPE FooFile=
ASSOC .foo=
EDIT: I've got a try now with something that enables you to re-set the association back to its default. I put it in my Subversion repo. In its current stage it generates two new batch files: set.cmd and reset.cmd; one of which sets a new association, the other reverses it. Rolling the set.cmd into the actual batch shouldn't be too difficult but it would have made testing here a hell, so I'll leave that as an exercise.
Code follows, it should be commented enough, hopefully.
#echo off
setlocal enableextensions enabledelayedexpansion
rem Debug flag. Generates a little more output; un-set if undesired
set DEBUG=1
rem Parse arguments and help
if [%1]==[] goto Usage
if [%2]==[] goto Usage
rem Find out whether the association is taken
for /f "usebackq tokens=2* delims==" %%x in (`assoc .%1 2^>nul`) do set assoc_old=%%x
if defined DEBUG (
if defined assoc_old (echo Association already defined: [%assoc_old%]) else (echo Association not yet taken)
)
rem Find a new, unused association
rem Note that we assume that we find one, eventually. This isn't guaranteed, but we'll ignore that for the moment
rem Otherwise this loop might run forever
:loop
set assoc_new=My.%1.%RANDOM%
if defined DEBUG echo Trying new association (%assoc_new%)
assoc .%1 >nul 2>nul
if errorlevel 1 (
set assoc_new=
if defined DEBUG echo Didn't work out
) else (
if defined DEBUG echo Found one! \o/
)
if not defined assoc_new goto loop
if defined DEBUG echo Writing reset batch file
echo #echo off>reset.cmd
echo assoc .%1=%assoc_old%>>reset.cmd
echo ftype %assoc_new%=>>reset.cmd
if defined DEBUG echo Writing setting batch file
echo #echo off>set.cmd
echo assoc .%1=%assoc_new%>>set.cmd
echo ftype %assoc_new%=%2 %%1>>set.cmd
goto :eof
:Usage
echo.Usage
echo. %~nx0 type command
echo.
echo. type is the file type to override, such as docx or txt.
echo. No dot before it is necessary.
echo. command is the command to perform on that file.
echo. %%1 is automatically appended at the end.
echo. If the command includes spaces, surround it with quotes.
echo.
echo.Example
echo. %~nx0 txt notepad
exit /b 1

Resources