I have a batch file that I am trying to get working and I'm having trouble suppressing the output of a couple of commands. One solution I've tried is to start the commands with the # symbol - (something I've done sucessfully plenty of times). Here is the code:
#echo off
setlocal
for /f "tokens=*" %%i in (tmp\hdata.txt) do (
::' just a note - hdata.txt contains lines of text such as,
::' for example:
::' jquery_javascript_32
::' underscore_javascript_9
::' I couldn't do this with simple delimiters because some lines are like:
::' underscore_js_javascript_43
set "id=%%i"
set filewithnum=!id:_javascript_=!
::' *** BELOW throws error ***
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!filewithnum:~,-1!" >nul 2>&1
::' *** BELOW throws error ***
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!file:~,-1!" >nul 2>&1
echo !file!
)
endlocal
exit /b
The lines commented above throw: '#echo' is not recognized as an internal or external command, operable program or batch file.
Seems weird.
Any ideas as to what's happening here?
Note: The extra ' after the comment :: above is to make syntax highlighting work properly on stackoverflow.
Once you've fixed the points Magoo raised in the comments, you need to suppress the output of findstr. You don't need # since command echo mode is already turned off at the start of the script.
You've got this:
#echo !filewithnum!|findstr /R "[0-9]$" && set "file=!filewithnum:~,-1!" >nul 2>&1
So you are redirecting the output of the set command! To redirect the output of findstr, do this:
echo !filewithnum!|findstr /R "[0-9]$" >nul 2>&1 && set "file=!filewithnum:~,-1!"
Related
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.
I am trying to take out the first line of a file called id.txt and setting it to a variable.
Set /p requestid=<id.txt
Which is giving me an error as below:
Set /p requestid=0<id.txt
Requestida was unexpected at this time.
Could anyone suggest me on this.
Why there is zero in front of shift left operator
What is the reason that the variable is not getting set with the first line of id.txt file.
Even though when I hit the same command over cmd it is working but in batch file it is getting stuck at this line with the above error.
Here is the full script:
cd C:\scripts\
dir .csr;.pem /B >csr.txt
for /f "tokens=*" %%a in (C:\scripts\csr.txt) do call :next
:next
If "%1"=="" goto end
certReq -submit -config machine_name -attrib "CertificateTemplate:XYZ" %1 %1.cer >id.txt
set /p Requid=<C:\scripts\id.txt
for /f "tokens=2 delims= " %a in ("%Requid%") do set Requid1=%a
Certutil -resubmit %Requid1%
:end
For question 1:
The 0 means STDIN (standard input). Check Standard streams for the concept.
0 is a File descriptor for stdin.
It's automatically added by the batch system, and it's not an error.
Question 2:
Your syntax seems okay, and I tested it's working. There must be other error.
However you can change it to another way:
for /f "delims=" %%i in (id.txt) do set "requestid=%%i" & goto :endfor
:endfor
I extracted the last line of a text file using the following command:
for /f "tokens=*" %%m in (message_log.txt) do (
Set lastline=%%m
)
My goal is if the variable %lastline%=="☺§☻PDF file has been aborted.
then to display one output and if not exit. But I think the first three characters are messing it up. I am trying this:
for /F "tokens=1-5 delims= " %%a in (%lastline%) do (
if %%e==aborted. (
echo pdf not filed
)
Pause
but the file just exits, with no pause and no output.
I can get this to work if instead of using %lastline% I refer to a file as I did in the first for loop, however I cannot get it to work with a variable.
What is the correct syntax to use a FOR loop to search inside a predefined variable?
If it is simpler my ultimate goal is to echo an error message if the last line in my text file contains the string "abort". Is there a better way to do this?
Your first approach is OK, just missing the check.
for /f "delims=" %%m in (message_log.txt) do Set lastline=%%m
If "%lastline%" neq "%lastline:abort=%" ^
Echo error message the last line in message_log.txt contains the string "abort"
With findstr
for /f "delims=" %%m in (message_log.txt) do Set lastline=%%m
Echo %lastline%|Findstr /i "abort" 2>&1 >Nul && ^
Echo error message the last line in message_log.txt contains the string "abort"
With Gnuwin32 tools installed
tail -n 1 message_log.txt|grep "abort" >NUL && ^
Echo error message the last line in message_log.txt contains the string "abort"
I found there are some topics similar to this problem but not exactly what I want, so I raise this topic.
I want to create a log function for printing message to both formatted log file and console output. The function is as below:
:LOGDEBUG
#echo DEBUG: %~1
if NOT EXIST %LOG_FILE% exit /b 1
#echo [%date - %time%] DEBUG: %~1 >> %LOG_FILE% 2>&1
exit /b 0
And I try to use it for printing the command execution output and if the output contains special character like "<" and ">", this function doesn't work well and prompt "The system cannot find the file specified". My code for executing a command is below:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
CALL :LOGDEBUG "%%a"
)
However, when I use "echo" command directly instead of the log function, the output can be printed correctly on the console. Like the following code:
for /f "usebackq delims=" %%a in (`dir c:\temp`) do (
echo %%a
)
May I know what is the problem, and how can I print the output correctly by using the log function? Thanks
You have answered your question by own: when I use "echo" command directly...
#ECHO OFF
SETLOCAL EnableExtensions
set "LOG_FILE=D:\tempx\program.log" my testing value
rem type NUL>"%LOG_FILE%"
for /f "usebackq delims=" %%a in (`dir d:\temp 2^>NUL`) do (
CALL :LOGDEBUG "%%a"
)
rem type "%LOG_FILE%"
ENDLOCAL
exit /b
:LOGDEBUG
FOR %%A in ("%~1") do (
#echo DEBUG: %%~A
if NOT EXIST "%LOG_FILE%" exit /b 1
#echo [%date% - %time%] DEBUG: %%~A >> "%LOG_FILE%" 2>&1
)
exit /b 0
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~A etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
Here is the batch code which should work.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do call :LOGDEBUG "%%a"
endlocal
goto :EOF
:LOGDEBUG
set "StringToOutput=%~1"
echo DEBUG: !StringToOutput!
echo [%DATE% - %TIME%] DEBUG: !StringToOutput!>>"%LOG_FILE%"
goto :EOF
First delayed environment variable expansion is enabled and a copy of existing environment table is made. It is explained below why this is done.
Next the name of the log file with full path is assigned to an environment variable in local variable table. This path can be with or without 1 or more spaces in path. The log file is deleted in case of existing already from a previous run. This code can be removed if you want to append new lines to already existing file. But you should add in this case code to avoid that the log file permanently increases until no free storage space anymore.
The FOR command executes the command DIR and processes each line of the output of DIR written to stdout. Blank lines are skipped. The default delimiters are space, tab and newline characters. As wanted here are the entire lines of DIR, the default delimiter list is replaced by nothing which means only newline characters remain and loop variable %a gets assigned always an entire non blank line.
The output of command DIR contains < and > which are interpreted as redirection operators if found by command processor within a line not quoted. Therefore the line for DIR output is passed quoted to subroutine LOGDEBUG. Which characters must be usually quoted are listed on last help page printed into a command prompt window when executing cmd /? in a command prompt window.
When the loop has finished, the local environment table is deleted which means LOG_FILE and StringToOutput are also removed, and previous environment is restored which usually means the delayed expansion is turned off again before batch execution exits with a jump to predefined label to end of file.
The subroutine LOGDEBUG first assigns the passed string to an environment variable without surrounding quotes just needed because of special characters in line like < and >.
Next the line is written to console window without quotes using delayed expansion as otherwise < and > would be interpreted as redirecting operators and not literally.
The same line is written also to the log file with the difference of date and time inserted at beginning of line. You missed the percent sign after date in your code. Again delayed expansion is used to get the line with the characters < and > written to file without being interpreted as redirection operators.
Important is also that there is no space before >> as otherwise each line in log file would have a trailing space. 2>&1 is useless here as command echo does not write something to stderr.
The subroutine is exited with a jump to end of file resulting in command FOR processes next line.
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 /?
del /?
dir /?
for /?
goto /?
set /?
It would be of course possible to do all the output directly in body of command FOR without using a subroutine.
#echo off
setlocal EnableDelayedExpansion
set "LOG_FILE=C:\program.log"
del "%LOG_FILE%" 2>nul
for /F "delims=" %%a in ('dir "C:\temp\*" 2^>nul') do (
echo DEBUG: %%a
echo [!DATE! - !TIME!] DEBUG: %%a>>"%LOG_FILE%"
)
endlocal
Delayed variable expansion is nevertheless required here as otherwise %DATE% and %TIME% would be expanded by command processor like %LOG_FILE% already on parsing entire block defined by ( and ) before command FOR is executed at all which would result in same date and time written for all lines to the log file.
I haven't worked with batch files before but I would like to create a batch file that runs a command line program which will output one of two lines depending on success or failure. Is there any way I can capture the executable's output without writing it to a temporary file?
Thanks in advance
put the program in a for /f loop (example):
for /f "delims=" %%a in ('myProgram.exe -a -b -c') do if /i "%%~a"=="failure" (call:dothis) else call:success
if %errorlevel%==0 call:success
if %errorlevel%==1 call:dothis
goto:eof
:dothis
echo Error found.
exit /b 1
:success
echo No error found.
exit /b 0