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"
Related
I need to find out if the given csv doesn't have any values other than header using batch script.
I'm trying with below line but my batch script is just flashing. Guide me to get the expected result.
(for /f "skip=1" %%a in ('type response.csv') do if "%%a"=="" (
set isDataPresent= No
echo %isDataPresent%
)
if %isDataPresent% EQU No goto noRecords
)
:noRecords
echo file is blank
[do something]
You have a delayed expansion problem.
May I suggest another (simpler) approach?
for /f "skip=1" %%a in (response.csv) do goto :data
echo no data.
goto :eof
:data
echo data available
If there is just one line (or no line at all), the do clause in for /f isn't even executed and the script continues with echo no data.. If there is a second line, the goto is executed (thus skipping the rest of the file)
Alternatively, you could use this approach:
#Set "}="&(Set /P "="&Set /P "}=")<"response.csv"&If Not Defined } Echo No Data
The idea is that the variable named } will be defined with the content of line 2 of response.csv. If that variable is not defined, it means that there was no content on line 2.
This is a little different to the answer already provided because if the second line was empty, and there was a line 3 with content, it would show as having no data. Therefore this example only reports no data on line 2, not no data beyond line 1.
If you want to report no data beyond line 1, here's another alternative:
findstr /N "^" "response.csv" 2>NUL|findstr /BL "2:">NUL||Echo No Data
Although I'd prefer to use full paths and names:
%SystemRoot%\System32\findstr.exe /N "^" "Response.csv" 2>NUL | %SystemRoot%\System32\findstr.exe /B /L "2:" 1>NUL || Echo No Data
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'm trying to read the output of a command (which outputs into multiple lines), and use an arbitrary number of those lines. Because I know neither the number of total lines, nor the number of lines that will be used, I need to analyse and possibly use each line in a loop, which is why I have setlocal enabledelayedexpansion.
Below is a snippet of the code that shows the process of taking the command and reading each line (not using it yet, just reading it to make sure this works (which it doesn't)):
#echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%i in ('svn status') do (
echo %%i
set file=%%i
echo *!file!
)
The problem that I'm running into is that the %%i values that are being read in are not correct in the for line. The first character is missing from the first line of the input (which is important because I use the first line to decide whether or not to use that line).
The output I get from my code looks like this:
Dir0\TestDoc7.txt
? StatusFile.txt
Whereas if I run this code:
copy /y NUL StatusFile.txt >NUL
>StatusFile.txt (
svn status
)
(Which is just another way of me seeing what the real output of svn status is) I get a proper output into the text file:
! Dir0\TestDoc7.txt
? StatusFile.txt
I'm probably making a fairly clear mistake as I'm rather new to batch scripting.
Thanks in advance.
The cause is EnableDelayedExpansion which will eat the exclamation marks,
Your choice of tokens=* will also strip all leading spaces from the lines.
#echo off
for /f "tokens=1*" %%A in ('svn status') do (
if "%%A" equ "!" (
Rem do whatever
) else If "%%A" equ "?" (
Rem do something else rest of the line is in %%B
) else (
Rem no ! or ? first space sep. content is in %%A rest of the line is in %%B
)
)
On Windows 10 I have this .bat:
#echo off
for /f "delims=" %%i in (filelist.txt) do (
echo %%~nxi >> output.txt
type "%%~ni*" >> output.txt
echo. >> output.txt
echo. >> output.txt
)
Exit
Now what this does is:
reads filelist.txt, which contains names of .txt files like:
20180808173105 (without ".txt"
searches for those files: 20180808173105.txt
copies name of files (without ".txt") into output.txt
inserts content of files
inserts two blank lines
repeats whole process for all files named in filelist.txt
--> It works fine! (or do you see any exception where this might malfunction?)
This inserts the full contents of a text file according to a list.
Can I modify it, so
not the whole content of a .txt, but only a part of it is inserted?
For example, everything from just after "title:" to just before "<!--"
if the filelist had a hierarchical structure (outline), it could
be preserved, like so:
#201508081213
###201609101219
to
#201508081213
TEXT
###201609101219
TEXT
I am using this to convert Outlines (using only the file names) to a rough first draft of text for writing articles and blogs
#echo off
2> output.txt echo.
#>&3 (
echo Debug Information
echo -----------------
)
for /f "delims=" %%A in (filelist.txt) do (
for %%B in ("%%~nA*") do call :read "%%~B"
) >> output.txt
exit /b
:read
setlocal
set "line="
echo(%~nx1
for /f "usebackq delims=" %%C in ("%~1") do (
set "line=%%C"
for /f "tokens=*" %%D in ('call echo "%%line:~0,4%%"') do (
#>&3 echo File: "%~1" Test: %%D == "<!--"
if %%D == "<!--" (
#>&3 echo Found: "<!--"
echo.
echo.
exit /b 0
)
)
call echo(%%line%%
)
echo.
echo.
exit /b 0
Note
Not the best language for this task. Had to avoid
enabledelayedexpansion as to known use of ! in <!--.
Used call even though < and some other characters
could cause issue.
for /f loops do not normally process empty lines so
hope that is not a problem.
Hierarchical structure depends on the order in filelist.txt.
The structure of a document can vary and I cannot consider
what the correct order might be. The use of a wildcard gives
some doubt. A filename #a will find #a1 and #a2 so
placement of 3 headings is unknown.
I have left in the std stream 3 messages for your
understanding of operation with the <!-- test.
Std stream 1 is the output that goes to file.
Operation
The file output.txt is erased before echoing text to the file.
The 1st for loop reads each line of the filelist.txt file.
The nested for loop gets the filenames with a wildcard.
Each call to label :read passes the argument of a filename.
In the label of :read, the filename is echoed.
A for loop reads lines from the filename.
Each line is stored in variable named line.
The nested for loop will use call echo to expand
the variable line and echoes the 1st 4 characters.
A comparison is done to test if it is <!-- and if so,
echo 2 newlines and then the label is exited.
If not, echo each line. echo 2 newlines is done at
the end of the label before exiting.
I am trying to find and replace. I am using a for loop. I am learning but I am almost there. I have tried to find the answer but the sources have been a bit too confusing for me.
The delim is a blank space and as you can tell I am skipping 4 lines and doing the 2nd token.
I need what is found there at that spot to be replaced by var5a. I have it backwards, as I need %%F to equal var5a, not the other way around (as I have it written now). But don't know how to write it. Please explain how one can do this. I've tried using <<= but with no luck.
for /f "skip=4 tokens=2 delims= " %%F in (script.vbs) do (
set var5a=!var5a!%%F
)
I'm learning so please be kind.
#ECHO OFF
SETLOCAL
:: Replace token 2 (space-separated) in line 5 of a file with REPLACEMENT
:: Assumed the file exists, etc. and no line begins ":"
SET replacement=THIS IS THE REPLACEMENT TEXT
DEL newfile.txt 2>nul
FOR /f "tokens=1*delims=:" %%i IN ('findstr /n /r "$" ^<oldfile.txt') DO (
IF %%i==5 (
FOR /f "tokens=1,2* delims= " %%L IN ("%%j") DO >>newfile.txt ECHO %%L %replacement% %%N
) ELSE (>>newfile.txt ECHO.%%j)
)
TYPE oldfile.txt
ECHO ==== separator =======
FC oldfile.txt newfile.txt
Results:
Line one should not be changed
Line two should not be changed
Line three should not be changed
Line four should not be changed
changeme iwillbereplaced but only on this line
and notbereplaced on subsequent lines
including the previous line which was empty
==== separator =======
Comparing files oldfile.txt and NEWFILE.TXT
***** oldfile.txt
Line four should not be changed
changeme iwillbereplaced but only on this line
and notbereplaced on subsequent lines
***** NEWFILE.TXT
Line four should not be changed
changeme THIS IS THE REPLACEMENT TEXT but only on this line
and notbereplaced on subsequent lines
*****
There are difficulties - especially if the lines in your file start with a colon or contain quoted-strings or any of the usual batch gotchas like %
So - at long last I've worked out what you're doing. You omitted the critical information that the string in %%F is not only quoted, it also contains spaces.
Had you said that in the first place, you'd be hours further into your project, and I'd be richer by a handful of aspirin.
In order to load %%F with a quoted string, I've read the string from a file.
#ECHO OFF
SETLOCAL enabledelayedexpansion
:: Replace token 2 (space-separated) in line 5 of a file with REPLACEMENT
:: Assumed the file exists, etc. and no line begins ":"
SET replacement="THIS IS THE REPLACEMENT TEXT"
DEL newfile.txt 2>NUL
:: iwbr.txt just contains
:: "i will be replaced"
:: on a single line for loading into %%F as that is the target to be replaced
FOR /f "delims=" %%F IN (iwbr.txt) DO (
FOR /f "tokens=1*delims=:" %%i IN (
'findstr /n /r "$" ^<oldfile.txt'
) DO >>newfile.txt (
IF %%i==5 (
SET newline=%%j
CALL SET newline=%%newline:%%F=%replacement%%%
ECHO.!newline!
) ELSE (ECHO.%%j)
)
)
TYPE oldfile.txt
ECHO ==== separator =======
FC oldfile.txt newfile.txt
Results:
Line one should not be changed
Line two should not be changed
Line three "should" not be changed
Line four should not be changed
changeme "i will bereplaced" but only on this line
and notbereplaced on subsequent lines
including the "previous" line which was empty
including this "unbalanced-quote line...
==== separator =======
Comparing files oldfile.txt and NEWFILE.TXT
***** oldfile.txt
Line four should not be changed
changeme "i will bereplaced" but only on this line
and notbereplaced on subsequent lines
***** NEWFILE.TXT
Line four should not be changed
changeme "THIS IS THE REPLACEMENT TEXT" but only on this line
and notbereplaced on subsequent lines
*****
If you have Henri in %%F and you want to set the value of Henri to the current value of var5a then
set %%F=!var5a!
(!var5a! if you want the RUN-TIME value of var5a (provided you have ENABLEDELAYEDEXPANSION mode invoked) or %var5a% if you want the PARSE-TIME value)
Program to demonstrate that the answer does work:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
::: WARNING! This will overwrite SCRIPT.VBS
DEL script.vbs 2>nul
FOR /l %%i IN (1,1,4) DO >>script.vbs ECHO ignore this line %%i
>>script.vbs ECHO Oh Henri - it does work
>>script.vbs ECHO Now try again
ECHO ===== here is script.vbs
TYPE script.vbs
ECHO ===== script.vbs ends
SET var5a=this is the value
SET henri
SET var5a
ECHO ===== now run the FOR loop...
for /f "skip=4 tokens=2 delims= " %%F in (script.vbs) do (
set %%F=!var5a!
)
SET henri
GOTO :eof
Results:
===== here is script.vbs
ignore this line 1
ignore this line 2
ignore this line 3
ignore this line 4
Oh Henri - it does work
Now try again
===== script.vbs ends
Environment variable henri not defined
var5a=this is the value
===== now run the FOR loop...
Henri=this is the value
Now - what do you mean by "it doesn't work"? It certainly does. If it's not doing what you want it to do, then demonstrate WHY you make the claim, otherwise we're left guessing.
For instance, the above will also set try to the value because Henri isn't the ONLY token that's number 2, space-delimited after 4 lines of the source file. That's easy to fix (but I'm not a mindreader - just a humble programmer)
(set notsetyet=Y)
for /f "skip=4 tokens=2 delims= " %%F in (script.vbs) do (
IF DEFINED NOTSETYET set %%F=!var5a!&(set notsetyet=)
)
But maybe "it didn't work" because it Henri was set to the wrong value. Or perhaps it crashed. We can't tell from your response.