I am using a batch file:
#echo off
C:\Octave\Octave-4.4.1\octave.vbs --force-gui --eval batchTest("'%~dp0'")
cmd /c
to run an Octave script
function [] = batchTest(fPath)
disp(fPath);
cd(fPath);
optionNumber = input('Choose option 1 or 2: ');
if optionNumber == 1
fName = input('Input file description: ',"s");
filename = [fName ".xlsx"];
xls = xlsopen(filename,1); % <-- THIS DOES NOT WORK, PRODUCES "FILE POINTER PRESERVED MESSAGE"
xls = oct2xls({"OutputData"},xls,1,"A1");
xlsclose(xls);
end
if optionNumber == 2
filename = "TestFile.xlsx";
xls = xlsopen(filename,1); % <-- THIS WORKS AS EXPECTED
xls = oct2xls({"OutputData"},xls,1,"A1");
xlsclose(xls);
end
to create an Excel file in the batch file's directory.
Option number 1 produces a "File pointer preserved" warning, and the Excel file is not created. It seems that I can't use any string that was created, in whole or in part, by Octave's 'input' function. Inputting the full filename with ".xlsx" and passing that variable to the 'xlsopen' function does not help. Option 2 works fine, but I need to produce multiple files, so the "fName" descriptor is important. I've tried adding SETLOCAL ENABLEDELAYEDEXPANSION to the batch file. I've also tried a work-around where I used Option 2, and then added
rename("TestFile.xlsx",[fName ".xlsx"])
to the Octave script, but this produces an "invalid input" error in the 'rename' function, so it doesn't like the 'input'-created string either. The problem is only with the 'xlsopen' and 'rename' functions; the 'input' function works just fine for choosing the option number.
Either option works when directly executing 'batchTest(pwd)' from the Octave command line. The issue only arises when executing from the batch file. Any advice would be much appreciated.
The issue sounds to be that when you create your string, you are including escaped characters that mess up your filename.
From the discussion in the comments it seems the carriage return character is being included in your string, resulting in a wrong filename.
It is unclear why this is only the case when running from the batch file, but as a workaround, you can ensure that the carriage return is removed by preprocessing your string input with strtrim to remove any unwanted whitespace.
Related
This question already exists:
How to pass a string to a Windows cmd that expects a file argument? [closed]
Closed 2 years ago.
Suppose a program cook takes one argument: the pathname of a text file containing the recipe of the food to cook. Suppose I wish to call this program from within a batch script, also suppose I already have the recipe in a string variable:
set the_recipe = "wash cucumbers" "wash knife" "slice cucumbers"
cook ... # What should I do here? It expects a file, but I only have a string.
Adapted from here.
How can I pass the recipe to the command when it expects a filename argument?
I thought about creating a temporary file just for the purpose passing a file, but I wish to know if there are alternative ways to solve this problem.
Unfortunately, Batch does not provide a mechanism similar to the Bourne shell heredoc. There are two ways to do this:
Option 1: Change the command
If you have access to the cook executable, you can add a flag to indicate passing a string or list of strings instead of a file. For example, COOK/A might take argument input, while COOK/F takes a file.
Option 2: Use a temporary file
Use a temporary file. The typical way to generate a temporary file is:
SET TEMPFILE=%TMP%\%~N0-%RANDOM%.tmp
ECHO.FILE CONTENT LINE 1 >> %TEMPFILE%
ECHO.FILE CONTENT LINE 2 >> %TEMPFILE%
REM AS MANY LINES AS ARE NEEDED
REM USE THE FILE
DEL/F "%TEMPFILE%" & REM DELETE THE TEMPORARY FILE
Remember that putting "" in an ECHO statement will cause the quotation marks to be included in the file, and that ECHO. must be used to include an indent in the file.
If you mean to convert the variable in your example into a tempfile with each quoted segment on a separate line, you'll need to use FOR:
FOR %A IN (%THE_RECIPE%) DO (
ECHO.%~A >> %TEMPFILE%
)
Including the ~ in the variable substitution strips out the quotation marks that would otherwise end up in the file. If you want the quotation marks in the file, you can omit the tilde.
I was making a batch file to take dragged-and-dropped folders for program input. Everything was working fine until I passed a folder, which for the sake of this post, called foo&bar.
Checking what %1 contained inside the batch file looked like C:\path\to\foo or C:\path\to\foo\foo. If the file path were in quotes it would work, so the only working code that slightly takes this into effect is :
set arg1=%1
cd %arg1%*
set arg1="%CD%"
Which changes directory to the passed argument using wildcards. However this only works once for if there is another folder with un-escaped characters inside the parent folder, passing the child folder would result in the parent folders' value.
I tried the answer of this post, which suggests to output the argument using a remark and redirection statement during an #echo on sequence. However no progress occurred in rectifying the problem. Any suggestions?
To recap, I am looking for ways to pass folders with un-escaped characters as arguments to a batch file. The implementation should preferably be in a batch file, but answers using VBScript are welcome. However the starting program must be in batch as this is the only program of the 3 that accepts files as arguments.
To test this, create a batch file with following code:
#echo off
set "arg1=%~1"
echo "the passed path was %arg1%"
pause
Then create folders called foobar and foo&bar. Drag them onto the batch file to see their output. foo&bar will only return C:\path\to\foo.
OK, so the problem is that Explorer is passing this as the command line to cmd.exe:
C:\Windows\system32\cmd.exe /c ""C:\path\test.bat" C:\path\foo&bar"
The outermost quotes get stripped, and the command becomes
"C:\working\so46635563\test.bat" C:\path\foo&bar
which cmd.exe interprets similarly to
("C:\working\so46635563\test.bat" C:\path\foo) & bar
i.e., bar is considered to be a separate command, to be run after the batch file.
The best solution would be to drag-and-drop not directly onto the batch file but onto, say, a vbscript or a Powershell script or a plain old executable. That script could then run the batch file, either quoting the argument appropriately or putting the directory path into an environment variable rather than on the command line.
Alternatively, you can retrieve the original command string from %CMDCMDLINE% like this:
setlocal EnableDelayedExpansion
set "dirname=!CMDCMDLINE!"
set "dirname=%dirname:&=?%"
set "dirname=%dirname:" =*%"
set "dirname=%dirname:"=*%"
set "dirname=%dirname: =/%"
for /F "tokens=3 delims=*" %%i in ("%dirname%") do set dirname=%%i
set "dirname=%dirname:/= %"
set "dirname=%dirname:?=&%"
set dirname
pause
exit
Note the exit at the end; that is necessary so that cmd.exe doesn't try to run bar when it reaches the end of the script. Otherwise, if the part of the directory name after the & happens to be a valid command, it could cause trouble.
NB: I'm not sure how robust this script is.
I've tested it with the most obvious combinations, but YMMV. [It might be more sensible to use delayed expansion exclusively, I'm not sure. It doesn't seem to be necessary except in the first set command. Jeb's answer here might be a better choice if you're going this route.]
For the curious, the script works like this:
Load the original command line into dirname [necessary for the reason pointed out by jeb]
Replace all the & characters with ?
Replace all the quote marks with *
If a quote mark is followed by a space, suppress the space.
NB: it is necessary to suppress the space to deal with both the case where the path contains a space (in which case Explorer adds quote marks around it) and the case where it doesn't.
Replace all remaining spaces with /
NB: ? * and / are illegal in file names, so these replacements are safe.
At this point the string looks like this:
C:\Windows\system32\cmd.exe//c/**C:\path\test.bat**C:\path\foo?bar**
So we just need to pull out the third asterisk-delimited element, turn any forward slashes back into spaces and any question marks back into ampersands, and we're done. Phew!
I'm trying to pass through caret chars through batch.
Escaping them once would be easy, but I need to do it twice.
I have an executable that will back up tables based on a Regex expression (not my code).
I want to back up all tables with an exclusion list.
Using ^(?!tableName$).* works for a single table.
Batch File 1 (called from command line)
SET ignoreTables=tableName
:: Call the backup script
CALL SecondBatch.bat %ignoreTables%
Batch File 2
:: Passthrough ignoreTables
Executable.exe --ignoreTablesPattern="^(?!%1$).*"
But I'd like to ignore multiple tables. In Regex this means using the | (pipe) character eg; tableOne|tableTwo would require;
SET ignoreTables=tableOne^|tableTwo
Which is correct at the SET but not when passed to the CALL
The correct output that works from the command line is;
Executable.exe --ignoreTablesPattern="^(?!tableOne|tableTwo$).*"
How can I get this result out of the batch file?
In batch file 1 use:
SET "ignoreTables=tableOne|tableTwo"
:: Call the backup script
CALL SecondBatch.bat "%ignoreTables%"
And in batch file 2 use:
:: Passthrough ignoreTables
Executable.exe --ignoreTablesPattern="^(?!%~1).*$"
Run in a command prompt window cmd /? and read the output help pages, especially the last paragraph on last help page which is about when surrounding a directory/file name or parameter string with double quotes is required.
The first line of batch file 1 contains the command SET with the parameter string variable=value. By enclosing this parameter string in double quotes the pipe character is not interpreted anymore as operator. For more details about using double quotes on assigning a string to an environment variable see answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The value of the environment variable is passed next expanded as first parameter to batch file 2. Again surrounding double quotes are needed to pass the string containing | as literal string to the second batch file.
In the second batch file it is necessary to reference the first argument without surrounding quotes. Therefore %~1 is used now instead of %1 as explained in help of command CALL output on running in a command prompt window call /?.
BTW: I'm quite sure $ should be at end of the regular expression and not inside the negative lookahead.
I'm new to programming so apologies in advance if this is really simple.
I'm using PA File Sight to monitor a folder for open files. When a file is opened it starts a program (batch file in this case) and passes the entire file path to the variable: $Item(1)$
The batch file looks like this at the moment:
set FILE_PATH="$Item(1)$"
echo.>%FILE_PATH%_IS_OPEN
I'm trying to get the batch file to create a new file with IS_OPEN on the end of it so that users know that a file "is open"
Running the batch file creates the following in it's folder:
$Item(1)$_IS_OPEN
So it's not storing the path for some reason.
I'd suggest you try
set FILE_PATH="%~1"
echo. "%FILE_PATH%_IS_OPEN"
echo.>"%FILE_PATH%_IS_OPEN"
PAUSE
This should set FILE_PATH to the first parameter that the batch file sees - the ~ removes any enclosing quotes
The next line echoes the result to the console and may be removed if the test proves successful.
The third line encloses the proposed filename in quotes to allow the use of spaces in the filename generated.
The PAUSE holds the CMD window open until you press ENTER to allow you to see the results. It too can be removed if your results are as expected.
modified to replace the first 2 characters of the NAME portion with "AA"
set FILE_PATH="%~1"
FOR /f "delims=" %%i IN ("%file_path%") DO (SET dpi=%%~dpi&SET ni=%%~ni&SET xi=%%~xi)
SET file_path=%dpi%AA%ni:~2%%xi%
echo. "%FILE_PATH%_IS_OPEN"
echo.>"%FILE_PATH%_IS_OPEN"
PAUSE
This assumes that it's the first 2 characters that need to be replaced. It works by assuming that the literal-string in the variable file_path is a filename whic, miracle of miracles, it is. dpi is then set to the drive and path, ni to the name and xi to the extension. then the full name is reconstructed, substituting AA for the first 2 characters of the name (dpi (the path) + AA + ni:2 (the name from the second character to the end) + xi (the extension))
$Item(1)$ seems like a constant string. If $Item(1)$ is the name of an actual environment variable, your first line should be
set FILE_PATH="%$Item(1)$%"
Although that seems quite an odd name for a variable.
I have tried prefixing lines with semicolons, 'REM', etc.. but no matter what when I run my batch file I keep getting "unknown command REM whatever"
"REM test" It is not recognized, and it is windows vista. I simply get "rem" output back to my console.
That's entirely normal behavior. Batch files are simply sequences of commands that are run one after another. So every line will get output to the console as if it were typed there.
H:\>echo rem test > test.cmd
H:\>test
yields the output
H:\>rem test
as if I typed rem test directly to the console.
You can suppress this by either prefixing the line with #:
#rem test
or by including echo off in the batch file:
#echo off
rem test
If I put ":: test" and execute it I get back "Test".
Can't reproduce here.
If I put "; test" it recursively executes itself
A semicolon at the start of the line seemingly gets ignored.
If you're talking about cmd.exe batch files under Windows, you can use:
rem this method or
:: this method.
For bash and a lot of other UNIX-type shells, you use:
# this method.
I'm pretty certain you're not using cmd.exe since that would give you an error like:
'rem' is not recognized as an internal or external command,
operable program or batch file.
rather then:
Unknown command ...
If you are using a UNIX-type shell, the # character is almost certainly what you're after. If you let us know exactly the shell you're using, we can probably help out further.
you probably created an UNICODE file. These files contain 2 bytes header named BOM
which is not shown by any editor but cmd attempts to execute them and fails.
To make sure this is indeed an issue: type any other command at the very beginning
of your file and see it throws the same error - for example #echo test
To fix it, just create a new plain text file and copy content of the original file there.
then remove the original file and replace it by the newly created one.
In my case the problems are line endings. Somehow Maven or the Jenkins pipeline running on a Linux machine changed the line endings from Windows style (CR LF) to Unix style (LF). Changing them back solves the issue for me.