i know this was already discussed but i didn't find what i needed.
I need to add new lines at the end of the hosts window file but,
first i need to check if these lines already exist and than adding them.
I tried this:
set "list=examp.com=examp2.com=examp3.com"
SET NEWLINE=^0.0.0.0
for %%a in (%list%) do (
FINDSTR /I %%a %WINDIR%\system32\drivers\etc\hosts)
IF %ERRORLEVEL% NEQ 0 (ECHO %NEWLINE% %%a>>%WINDIR%\System32\drivers\etc\hosts)
pause
but the result in hosts is just 1 line like this:
0.0.0.0 %a
I also want to know if it's possible to change this:
set "list=examp.com=examp2.com=examp3.com"
with another code that will take variables from a txt file.
Your code is not quite as bad as Mofi would suggest. Although it's quite uncommon to use an equal sign as a delimiter for a for loop, it is nevertheless legal syntax. The largest two problems I see are that you're closing your for loop at the end of your findstr statement; and, assuming you fix that, %ERRORLEVEL% would need its expansion delayed. Or you could use the if errorlevel syntax of the if statement (see help if in a cmd console for full details`). Or even better, use conditional execution.
Here's an example using conditional execution. This example also opens your HOSTS file for appending one time, rather than one time for each loop iteration -- a subtle efficiency improvement, true, but a worthwhile habit to practice when writing files with a loop. And because HOSTS by default has attributes set to prevent writing, I stored and removed the read-only / system / hidden / etc. attributes of the hosts file, appended the changes to the file, then restored the attributes back the way they were before.
#echo off & setlocal
set "hosts=%WINDIR%\system32\drivers\etc\hosts"
set "list=examp.com=examp2.com=examp3.com"
SET "NEWLINE=0.0.0.0"
for /f "delims=" %%I in ('attrib "%hosts%"') do set "raw=%%~I"
setlocal enabledelayedexpansion
for /L %%I in (0,1,18) do if not "!raw:~%%I,1!"==" " set "attrs=!attrs!+!raw:~%%I,1! "
endlocal & set "attrs=%attrs%"
attrib -h -s -r -o -i -x -p -u "%hosts%"
>>"%hosts%" (
for %%a in (%list%) do (
>NUL 2>NUL find /I "%%a" "%hosts%" || echo(%NEWLINE% %%a
)
)
attrib %attrs% "%hosts%"
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
)
)
ECHO OFF
setlocal enabledelayedexpansion
CD C:\Work\
FOR /D /r %%G in ("t*") DO (
START C:\prg.exe %%G\input_1 %%G\input_2 %%G\cpp_output
FOR /D /r %%H in (%%G\cpp_output\*.txt) DO (
FOR /F %%i in ("%%H") DO (
#set FN=%%~nxi DO (
START C:\Work\compareResults.m %%G\matlab_output\FN.txt %%G\cpp_output\FN.txt
)
)
)
)
PAUSE
I have been trying to get this .bat code to run but it doesn't work - a window opens and closes quickly - i.e prg is not run. However, when I run:
ECHO OFF
setlocal enabledelayedexpansion
CD C:\Work\
FOR /D /r %%G in ("t*") DO (
START C:\prg.exe %%G\input_1 %%G\input_2 %%G\cpp_output
)
PAUSE
prg is run. I guess there seems to be a problem with the extra commands but I just don't know what the problem is.
According to http://ss64.com/nt/for.html one can have a few commands in a single for and they can be in different lines. However that didn't work so I tried using & to have multiple commands and I've also tried using the caret (^) for breaking lines. None of these seem to work and I can't even really debug anything since the batch window disappears too fast. Any ideas for what I am doing wrong? Or even how to debug the .bat program?
...
#set FN=%%~nxi DO(
START C:\Work\compareResults.m %%G\matlab_output\FN.txt %%G\cpp_output\FN.txt))))
This won't work. This is bad syntax. DO can't stand behind a SET command. In your case DO goes only with FOR:
FOR something DO (
codeline 1
codeline 2
...
codeline n
)
If you want several command lines to be executed within a FOR block you just have to write them between the brackets (), each command in a new line.
However, there is also a way to combine several commands in only one line (don't use it here): command1&command2&...comandn will execute commands 1 to n one after the other. They will be executed even if one of the commands throws an error. If you use && instead (command1&&command2&&...comandn), each command will only be executed if the previous command was proceeded without errors.
I'm not very familiar with BAT files but I have a file that runs a sqlplus query, returns the row count, and if it is greater than 0, run another bat file. I feel like I'm almost there but I keep getting this error:
%%a was unexpected at this time
#echo off
for /f "delims=" %%a in (
'sqlplus USER/PASS#OMP1 #VoiceBlockTrig.SQL'
) do set rowcount=%%a
if %ROWCOUNT% GTR 0 (
c:\SQLTRIGGERS\VoiceBlkAutoationBAT.bat
)
when I run the above, I get this as a reponse:
#echo off
for /f "delims=" %%a in (
%%a was unexpected at this time
'sqlplus USER/PASS#OMP1 #VoiceBlockTrig.SQL'
''sqlplus' is not recognized as an internal or external command, operable program or batch file
) do set rowcount=%%a
if %ROWCOUNT% GTR 0 (
More? c:\SQLTRIGGERS\VoiceBlkAutoationBAT.bat
More?
when I run this:
sqlplus user/pass#P1 #VoiceBlockTrig.SQL
I do get an integer value back too
why is there such a gap between the SET and rowcount?
In itself, it's of no matter - but I suspect that you have them on separate lines.
The set rowcount=%%a must all be on the same physical line as the do - and the do must be on the same physical line as the closing parenthesis after the in
for /f "delims=" %%a in (
'sqlplus user/pass#P1 #VoiceBlockTrig.SQL'
) do set rowcount=%%a
if perfectly legitimate.
As a .bat file:
:: #echo off
echo starting SQLPLUS
sqlplus USER/PASS#OMP1 #VoiceBlockTrig.SQL
echo finished SQLPLUS
for /f "delims=" %%a in (
'sqlplus USER/PASS#OMP1 #VoiceBlockTrig.SQL'
) do ECHO(+%%a+&set /A rowcount=%%a
ECHO rowcount=+%rowcount%+
if %ROWCOUNT% GTR 0 (
c:\SQLTRIGGERS\VoiceBlkAutoationBAT.bat
)
PAUSE
This is the batch that appears to be close to what you'd need to run.
The changes are:
added ECHO(+%%a+ in the FOR loop.
The open-parenthesis following the ECHO is simply a character that has been found to be better than SPACE to separate the ECHO from the text-to-be-echoed
The + before and after the %%a simply delimits the string with an
obvious character so that the presence of SPACES can be more easily observed.
SET changed to SET /A which interprets the value assigned as a
numeric-string, which should overcome any stray spaces in the
assignment.
Added ECHO of the rowcount within delimiters for visibility
Added PAUSE to stop the procedure from closing before you have a chance to see the results.
Comment : Probably the "delims=" is not required, but we'll get to that when the problems are defeated.
Comment: Your report that the script required TWO ENTERs could mean that the SQLPLUS is asking for input. If so, 'ECHO.^|sqlplus... may alleviate the problem.
If SQLPLUS is a BATCH, a different approach would need to be made.
Further changes to attempt to solve puzzing result:
Double-colon before #echo off - double-colon is often used as a
comment. The object is to show the lines being executed.
Added the SQLPLUS command independently - to observe results.
Added two ECHO lines to display progress.
Certainly very odd....
Any ideas how to echo or type the last 10 lines of a txt file?
I'm running a server change log script to prompt admins to state what they're doing, so we can track changes. I'm trying to get the script to show the last 10 entries or so to give an idea of what's been happening recently. I've found a script that deals with the last line, as shown below, but can't figure out what to change in it to display the last 10 lines.
Script:
#echo off
setLocal EnableDelayedExpansion
for /f "tokens=* delims= " %%a in (c:\log09.txt) do (
set var=%%a
)
echo !var!
Example of log file:
06/02/2009, 12:22,Remote=Workstation-9,Local=,
mdb,bouncing box after updates,CAS-08754,
=================
07/02/2009, 2:38,Remote=,Local=SERVER1,
mdb,just finished ghosting c drive,CAS-08776,
=================
07/02/2009, 3:09,Remote=,Local=SERVER1,
mdb,audit of server,CAS-08776,
Any thoughts?
The script works great, just need it to pipe more lines to the screen.
Hopefully this will save Joel's eyes :)
#echo OFF
:: Get the number of lines in the file
set LINES=0
for /f "delims==" %%I in (data.txt) do (
set /a LINES=LINES+1
)
:: Print the last 10 lines (suggestion to use more courtsey of dmityugov)
set /a LINES=LINES-10
more +%LINES% < data.txt
This answer combines the best features of already existing answers, and adds a few twists.
The solution is a simple batch implementation of the tail command.
The first argument is the file name (possibly with path information - be sure to enclose in quotes if any portion of path contains spaces or other problematic characters).
The second argument is the number of lines to print.
Finally any of the standard MORE options can be appended: /E /C /P /S /Tn. (See MORE /? for more information).
Additionally the /N (no pause) option can be specified to cause the output to be printed continuosly without pausing.
The solution first uses FIND to quickly count the number of lines. The file is passed in via redirected input instead of using a filename argument in order to eliminate the printout of the filename in the FIND output.
The number of lines to skip is computed with SET /A, but then it resets the number to 0 if it is less than 0.
Finally uses MORE to print out the desired lines after skipping the unwanted lines. MORE will pause after each screen's worth of lines unless the output is redirected to a file or piped to another command. The /N option avoids the pauses by piping the MORE output to FINDSTR with a regex that matches all lines. It is important to use FINDSTR instead of FIND because FIND can truncate long lines.
:: tail.bat File Num [/N|/E|/C|/P|/S|/Tn]...
::
:: Prints the last Num lines of text file File.
::
:: The output will pause after filling the screen unless the /N option
:: is specified
::
:: The standard MORE options /E /C /P /S /Tn can be specified.
:: See MORE /? for more information
::
#echo OFF
setlocal
set file=%1
set "cnt=%~2"
shift /1
shift /1
set "options="
set "noPause="
:parseOptions
if "%~1" neq "" (
if /i "%~1" equ "/N" (set noPause=^| findstr "^") else set options=%options% %~1
shift /1
goto :parseOptions
)
for /f %%N in ('find /c /v "" ^<%file%') do set skip=%%N
set /a "skip-=%cnt%"
if %skip% lss 0 set skip=0
more +%skip% %options% %file% %noPause%
You should probably just find a good implementation of tail. But if you really really insist on using CMD batch files and want to run on any NT machine unmolested, this will work:
#echo off
setLocal EnableDelayedExpansion
for /f "tokens=* delims= " %%a in (c:\tmp\foo.txt) do (
set var9=!var8!
set var8=!var7!
set var7=!var6!
set var6=!var5!
set var5=!var4!
set var4=!var3!
set var3=!var2!
set var2=!var1!
set var1=!var!
set var=%%a
)
echo !var9!
echo !var8!
echo !var7!
echo !var6!
echo !var5!
echo !var4!
echo !var3!
echo !var2!
echo !var1!
echo !var!
There are several windows implementations of the tail command. It should be exactly what you want.
This one sounds particularly good:
http://malektips.com/xp_dos_0001.html
They range from real-time monitoring to the last x lines of the file.
Edit: I noticed that the included link is to a package It should work, but here are some more versions:
http://www.lostinthebox.com/viewtopic.php?f=5&t=3801
http://sourceforge.net/projects/tailforwin32
If file is too large it can take too long to get count of lines
another way is to use find and pass it a nowhere string
$find /v /c "%%$%!" yourtextfile.txt
this would result an output like this
$---------- yourtextfile.txt: 140
then you can parse output using for like this
$for /f "tokens=3" %i in ('find /v /c "%%$%!" tt.txt') do set countoflines=%i
then you can substract ten lines from the total lines
After trying all of the answers I found on this page none of them worked on my file with 15539 lines.
However I found the answer here to work great. Copied into this post for convenience.
#echo off
for /f %%i in ('find /v /c "" ^< C:\path\to\textfile.txt') do set /a lines=%%i
set /a startLine=%lines% - 10
more /e +%startLine% C:\path\to\textfile.txt
This code will print the last 10 lines in the "C:\path\to\textfile.txt" file.
Credit goes to OP #Peter Mortensen
using a single powershell command:
powershell -nologo "& "Get-Content -Path c:\logFile.log -Tail 10"
applies to powershell 3.0 and newer
I agree with "You should use TAIL" answer. But it does not come by default on Windows. I suggest you download the "Windows 2003 Resource Kit" It works on XP/W2003 and more.
If you don't want to install on your server, you can install the resource kit on another machine and copy only TAIL.EXE to your server. Usage is sooooo much easier.
C:\> TAIL -10 myfile.txt
Here's a utility written in pure batch that can show a lines of file within a given range.To show the last lines use (here the script is named tailhead.bat):
call tailhead.bat -file "file.txt" -begin -10
Any ideas how to echo or type the last
10 lines of a txt file?
The following 3-liner script will list the last n lines from input file. n and file name/path are passed as input arguments.
# Script last.txt
var str file, content ; var int n, count
cat $file > $content ; set count = { len -e $content } - $n
stex -e ("["+makestr(int($count))) $content
The script is in biterscripting. To use, download biterscripting from http://www.biterscripting.com , save this script as C:\Scripts\last.txt, start biterscripting, enter the following command.
script last.txt file("c:\log09.txt") n(10)
The above will list last 10 lines from file c:\log09.txt. To list last 20 lines from the same file, use the following command.
script last.txt file("c:\log09.txt") n(20)
To list last 30 lines from a different file C:\folder1\somefile.log, use the following command.
script last.txt file("C:\folder1\somefile.log") n(30)
I wrote the script in a fairly generic way, so it can be used in various ways. Feel free to translate into another scripting/batch language.