THE ISSUE
This may just stem from a lack of deep understanding of Windows batch file coding.
I am trying to write a simple one-line batch file that will process every file in a directory using pandoc to convert all doc or docx (MS Word) files to markdown (.md) files. When I run my batch file I get the following error:
pandoc: C:_ALL\_ALL\accomp\testing-accomp-2017.05\20170505.md: openBinaryFile: does not exist (No such file or directory)
I get one of these errors for each file in the directory (around 25, or so).
The directory I'm running my command in looks like this:
C:\_ALL\!accomp\testing-accomp-2017.05
As you can see, for some reason the _ALL is appearing twice. The path it is showing me isn't right for some reason and I'm not sure if it is a pandoc issue or a CMD batch file programming issue.
MY CODE
Here is the code for my batch file:
#echo OFF
:: [Not sure what this does, but have read that it is necessary]
setlocal enabledelayedexpansion
:: MAIN
FOR /r "." %%i IN (*.doc *.docx) DO pandoc -f rst -t markdown "%%~fi" -o "%%~dpni.md"
:: End with a pause so user can copy any text from screen.
ECHO. Done. Press any key to terminate program
PAUSE>NUL
Now, I'm not certain what all these lines of code do, and they may be entirely unnecessary for all I know. However, the main and most important code here is the one that starts with For ..., which is inspired by this Stack Overflow post:
Batch processing Pandoc conversions in Windows
WHAT I'VE TRIED ALREADY
Basically there are about four variations of the same answer in the above linked post and I've tried each of those variations.
The error is caused by delayed expansion and the exclamation mark ! in directory name !accomp.
The command line to execute by FOR expands during execution with file 20170505.doc to:
pandoc -f rst -t markdown "C:\_ALL\!accomp\testing-accomp-2017.05\20170505.doc" -o "C:\_ALL\!accomp\testing-accomp-2017.05\20170505.md"
This command line is parsed by Windows command processor a second time before execution because of enabled delayed environment variable expansion, searching for !variable! reference and replacing them with value of referenced variables.
The string !accomp\testing-accomp-2017.05\20170505.doc" -o "C:\_ALL\! is completely misinterpreted here because of the exclamation marks. So finally executed is:
pandoc -f rst -t markdown "C:\_ALL\\_ALL\accomp\testing-accomp-2017.05\20170505.md"
And the file C:\_ALL\\_ALL\accomp\testing-accomp-2017.05\20170505.md does not exist.
The solution is removing setlocal enabledelayedexpansion as not needed here because of no environment variable used on FOR command line.
#ECHO OFF
FOR /r "." %%i IN (*.doc *.docx) DO pandoc.exe -f rst -t markdown "%%i" -o "%%~dpni.md"
:: End with a pause so user can copy any text from screen.
ECHO Done. Press any key to terminate program ...
PAUSE>NUL
The loop variable i holds here already the full qualified file name. Therefore "%%~fi" can be replaced by "%%i".
And it is better to use ECHO/ instead of ECHO. although neither . nor / is needed here. See DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the reason.
Related
I'm trying to write a batch file to act as an interface between Source-Insight, and Git running on a Linux server, but I'm running into an issue where the set /p does not seem to be working as advertised.
The batch file is supposed to run a linux script (via plink), which will check out the appropriate files into two directories, and then invoke Beyond Compare to compare the directories (note, these are on an sftp mounted drive so that dos can see them). The directory names are dynamic, so I need the batch file to read the generated directory name from a file before passing it to Beyond Compare. I can't seem to get this working...
I have the following lines in my batch script:
#echo on
plink server1234 -l %user% -i %ppk_file% "cd %root%; ~/bin/compare_git_all.sh --debug --ref"
echo "set /p dir=<%dosroot%\.comparegit.dosdir"
set /p dir=<%dosroot%\.comparegit.dosdir
echo dir="%dir%" (from %dosroot%\.comparegit.dosdir)
"C:\Program Files\Beyond Compare 4\BCompare.exe" %dir%.refpt %dir%
#echo off
My output ends up being:
"set /p dir=<z:\builddir\pd2\wt1\.comparegit.dosdir"
dir="" (from z:\builddir\pd2\wt1\.comparegit.dosdir)
So first issue (annoyance really), is that #echo on is not causing the commands to be echoed (which according to the pages I've google it's supposed to do...)
But what's killing me is that %dir% seems to be blank. I've verified that the file contains the data I am looking for:
C:\>more z:\builddir\pd2\wt1\.comparegit.dosdir
z:\builddir\pd2\wt1\.comparegit.zmP8BK
if I run the same command from a Command Prompt, I get:
C:\>set dir=blank
C:\>echo %dir%
blank
C:\>set /p dir=<z:\builddir\pd2\wt1\.comparegit.dosdir
C:\>echo %dir%
z:\builddir\pd2\wt1\.comparegit.zmP8BK
So, I'm missing something, but I'm not sure what it is. Any help would be appreciated. (note, if it makes any difference, the batch file is being invoked from a keymapping within Source Insight)
I have the following batch file to make git diff invoke spreadsheet compare UI in windows. So I'm trying to pass the git diff's 2nd (old file) and 5th (new file) arguments to spreadsheet compare in order to make it compare the file using git diff.
So now, this batch file only successfully handles files with NO spaces in the file names, it CANNOT handle files with spaces in the file names.
What code should I add to this script to make this batch code handles file with spaces:
#ECHO OFF
set path2=%5
set path2=%path2:/=\%
ECHO %2 > tmp.txt
dir %path2% /B /S >> tmp.txt
C:/"Program Files"/"Microsoft Office"/root/vfs/ProgramFilesX86/"Microsoft Office"/Office16/DCF/SPREADSHEETCOMPARE.EXE tmp.txt
It currently throw errors like this:
Unhandled Exception: System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.GetFileName(String path)
at ProdianceExcelCompare.Form1.StatusReady()
at ProdianceExcelCompare.Form1.Init()
at ProdianceExcelCompare.Form1..ctor(String instructionFile)
at ProdianceExcelCompare.Program.Main(String[] args)
fatal: external diff died, stopping at London comparison.xlsx
See the following answers on Stack Overflow:
How to set environment variables with spaces?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
They explain the recommended syntax set "VariableName=variable value" to define an environment variable and the reasons recommending this syntax.
Why does ECHO command print some extra trailing space into the file?
It explains why the space character left to redirection operator > on an ECHO command line is also written into the file as trailing space and how to avoid this safely on variable text written into the file.
See also Microsoft documentation about Using command redirection operators.
On other command lines than ECHO a space left to > is usually no problem.
It is in general wrong to use multiple times " within an argument string like a file or folder path. There should be just one " at beginning and one " at end. This is explained by help of Windows command processor output on last help page on running in a command prompt window cmd /?.
The Microsoft documentation about Naming Files, Paths, and Namespaces explains that the directory separator on Windows is \ and not / and therefore / should not be used in batch files on Windows in file/folder paths.
The help output on running in a command prompt window call /? explains how the arguments of a batch file can be referenced with which modifiers.
The code rewritten according to information posted above and on the referenced pages:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
>"tmp.txt" echo %2
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
The first line in tmp.txt contains the second argument as passed to the batch file, i.e. without or with surrounding double quotes.
The following code is necessary to write the second argument safely always without " into file tmp.txt even on second argument passed to the batch file is "Hello & welcome!":
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
set "Argument2=%~2"
setlocal EnableDelayedExpansion
echo !Argument2!>"tmp.txt"
endlocal
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
>tmp.txt echo %~2 cannot be used as not working for something like "Hello & welcome!". Windows command processor would interpret the first string separated by normal space, horizontal tab, comma, equal sign, or no-break space (in OEM code pages) delimited string after & as command or application to execute as described by single line with multiple commands using Windows batch file.
"tmp.txt" could be written everywhere in both batch files also with just tmp.txt. But it is never wrong to enclose the complete file/folder argument string in double quotes even on not being really necessary because of the string does not contain a space or one of these characters &()[]{}^=;!'+,`~. So it is good practice to always enclose a complete file/folder argument string in double quotes. For example running a replace on both batch files searching for tmp.txt and using as replace string %TEMP%\%~n0.tmp would result in using instead of tmp.txt in current directory a temporary file with name of batch file as file name and file extension .tmp in directory for temporary files independent on what is the name of the batch file and what is the path of the directory for temporary files.
The last suggestion is reading this answer for details about the commands SETLOCAL and ENDLOCAL.
The temporary file should be also deleted finally before reaching an exit point for batch file execution.
You can use quotes as below:
It treats the string in quotes as a title of the new command window. So, you may do the following:
start "" "yourpath"
Found it in the below link :
https://ccm.net/forum/affich-16973-open-a-file-with-spaces-from-batch-file
I'm creating a batch script to a get a file based on what option the user chooses. The only problem is, the file in the ftp server has a colon and from what i've researched, windows does not accept ":" colon.
Is it possible to replace that character before downloading?
Below is a sample of my code.
Echo open sample.net>first.dat
Echo user>>first.dat
Echo password>>first.dat
Echo ascii>>first.dat
Echo cd directory>>first.dat
Echo lcd folder>>first.dat
Echo get sample-text-10-16-2017_16:36:00:340033.txt>>first.dat
Echo bye>>first.dat
ftp -v -i -s:first.dat
del first.dat
As you can see also, I get a list first of the file names inside the folder for the user to input the file name. I just wrote a specific file name for the example
I'm still not familiar with the for loops in batch but I think that it is one way of replacing the characters in a file name before downloading
[Untried]
get remotefilename localfilename
is apparently valid, so placing a valid windows filename as a second argument should d/l to the file specified.
[Addendum - also untried]
(after Echo lcd folder>>first.dat)
echo mls remotefilesrequired awindowlistfilename>>first.dat
rem this should log in and create awindowslistfilename
rem containing the remote filelist
ftp -v -i -s:first.dat
del second.dat 2>nul
setlocal enabledelayedexpansion
for /f "delims=" %%a in (awindowslistfilename) do (
set "remote=%%a"
echo get !remote! !remote::=.!>>second.dat
)
endlocal
Echo bye>>second.dat
ftp -v -i -s:second.dat
del first.dat
del second.dat
Since I'm not aware of the return format for mls, I'm assuming that it's a simple file-list, one to a line.
This code first executes the ftp log-on palaver and an mls command, creating awindowslistfile locally.
It then deletes second.dat (the 2>nul suppresses error messages like file not found appearing on stderr)
setlocal enabledelayedexpansion and endlocal bracket a mode where the syntax changes such that !var! may be used to access the run-time value of a variable, whereas %var% always refers to the parse-time value.
The for/f command reads the filename (parenthesised) and assigns each line in turn to the metavariable %%a. The delims= option ensures that the entire line is assigned, ignoring the normal tokenising procedure.
A series of individual get commands is then written to second.dat, with the substitution of : by . in the name.
Finally, add the bye and FTP again.
(I'm not sure whether first.dat will also require a bye and second.bat will need to prelimnary commands, but could be...)
Note that it's batch convention to enclose filenames that may contain separators like Space,; in "quotes". How FTP will feel about that, if necessary, I can only guess.
Naturally, extra lines within the loop
set "remote=!remote:x=y!"
could be used to serially replace character sequences x by y if there are any other problematic characters encountered.
I am trying to write a log that a user will create in a batch file, as a small little game, but I can't seem to get the correct directory of the file down. I want to write to this directory:
BatchfileandFolder\subfolder1\subfolder2\ThedataisHere.txt
This is the code I have (I really don't know what I am doing)
Echo Write a piece of text here
set /p UserData=
>>\subfolder1\subfolder2\"ThedataisHere.txt" echo %UserData%
It is essential trying to dig deeper into the directory, but I don't know the exact command, and the help menu for CD, and PATH on the cmd.exe promt don't really help me that much.
Thank you for real human contact, speaking real English
#ECHO OFF
SETLOCAL
SET "logfile=u:\sub folder1\sub folder2\ThedataisHere.txt"
FOR /f "delims=" %%a IN ("%logfile%") DO MD "%%~dpa"
Echo Write a piece of text here
set /p UserData=
>>"%logfile%" echo %UserData%
GOTO :EOF
This method uses a variable logfile so that you aren't forever typing out the name (and avoid the pain if you want to change the names or directories, and the method allows you yo use multiple logfiles easily if you want)
I've deliberately used spaces in directory names to prove the method. The directory gets created immediately after the logfile name is set
append 2>nul to the md instruction line to suppress the directory already exists message
From there, simply use >>"%logfile%" to create the log. The quotes are not required if the filename doesn't contain separators like spaces.
Note that if the first character of the directory specified is \ then the directory is relative to the root, but if it is not then the directory is relative to the current directory on the destination drive. u: is a drive specifier, not a directoryname; I use u: as my test drive. Your choice is up to you.
If the directory structure already exists, it's pretty simple:
#echo off
set /p UserData=Write some text here:
#echo %UserData% >> "subfolder1\subfolder2\TheDataIsHere.txt"
If it doesn't exist already, you have to create it first (tested on Win7 64 bit):
#echo off
if not exist "subfolder1" md "subfolder1"
if not exist "subfolder1\subfolder2" md "subfolder1\subfolder2"
set /p UserData=Write some text here:
#echo %UserData% >> "subfolder1\subfolder2\TheDataIsHere.txt"
Although your description is ample, some important points are missing. It is obvious that you know "How to change the directory that a batch file will output text to", because you use the >> \subfolder\... notation, so this is not your problem. I can only guess that you want to know "How to get the directory where a batch file is located", so you can write to a log file placed two levels below that directory. If this is your problem, then you may use the %~P0 notation, that represent the path of the batch file; that is:
>> "%~P0subfolder1\subfolder2\ThedataisHere.txt" echo %UserData%
Note that the value returned by %~P0 ends in a backslash, so %~P0 must not be separated by an additional backslash from subfolder1; also note that the quotes must enclose the whole path of the file.
If this is not what you want, please carefully describe your real problem. Anyway, try to be clearer in future questions.
**Batch file **I am writing batch file that takes in command line parameters and do some stuff if the parameters match. But when the run the batch file again with the new parameters, the file still runs with the old parameters.
first run : file.bat -name hello -w 400 -r 320
second run : file.bat -name hello -w 400.
When i do the second run of the file, it still performs the first run, i mean to say it still considers the parameters from the first run. Does anybody know why this is the case?
Thanks in advance.
Sorry for not posting the batch file code.
below mentioned is the code.
set filename=
set rate=
set hidden=
set rate=
:recheck
if "%1"=="-help" goto :help
if "%1"=="-name" goto :filename
if "%1"=="-h" goto :hidden
if "%1"=="-w" goto :weight
if "%1"=="-r" goto :rate
if "%~1"=="" goto :endofcommandline
:filename
shift
set filename =%1
shift
goto :recheck
For the other part of the file, I use the variable "filename" to do other stuff. I also use setlocal and endlocal at the beginning and the end of the file.
I have other corresponding labels for the each if statement and set different variables to the values passed to them if any by the user.
Sometimes, I also get echo is off when I try to print out the value of some variable.
All the variables which I use are cleared in the beginning of the file as mentioned above.
There are a couple points here.
"I also use setlocal and endlocal at the beginning and the end of the file."
"All the variables which I use are cleared in the beginning of the file as mentioned above."
Setlocal command does NOT clear the variables, it preserve current variables from posterior modification. This mean that if in a previous execution of your Batch file, or even via typed SET commands, filename variable was defined, it value remains until it is deleted or modified.
"Ok!", you said, "filename variable is modified the second time the Batch file run, Right?"
Well, no... The following line:
set filename =%1
does NOT modify "filename" variable, but "filename " instead (filename and a space). Try this:
set filename=No space
echo %filename%
set filename =Bad name with trailing space
echo %filename %
echo %filename%
You must carefully check your program to avoid this type of errors.