Find current console size in batch - batch-file

I am working on a batch file and i need to print hyphens ( - ) across the screen as a separator. Is there a fast (under two seconds) command that can do this?
I have done multiple search queries and could not find the answer on various websites.
(code to find screen size)
for /l %%a in (1,1,%screen size var%) do (set "line=%line%-")
echo %line%
The output should show a line of hyphens across the console.

This is untested, but based upon the output from Mode CON as used in gjpio's answer:
#Echo Off
For /F "Skip=4Tokens=1*Delims=:" %%A In ('Mode CON')Do (For /L %%C In (1,1,%%B)Do #Set/P "=-"<Nul)&Echo( &GoTo :Draw
:Draw
Pause
If you intend to use the separator multiple times within your script you could save it to a variable:
#Echo Off
For /F "Skip=4Tokens=1*Delims=:" %%A In ('Mode CON')Do (For /L %%C In (1,1,%%B)Do (Call Set "separator=%%separator%%-"))&GoTo :Next
:Next
Echo Welcome to %~nx0
Echo %separator%
Pause
As a final afterthought, and just in case you feel that it would perform quicker, I thought I'd better provide a version using delayed expansion too:
#Echo Off&SetLocal EnableDelayedExpansion&Set "separator="
For /F "Skip=4Tokens=1*Delims=:" %%A In ('Mode CON')Do (For /L %%C In (1,1,%%B)Do Set "separator=!separator!-")&GoTo :Next
:Next
Rem Uncomment the next line if you don't want to use delayed expansion in the rest of the script
::EndLocal&Set "separator=%separator%"
Rem Your code goes here
Echo Welcome to %~nx0
Echo %separator%
Pause
As an addition to all of the above, you could also leverage powershell to do this too:
#Echo Off
For /F %%A In ('Powershell -NoP "Write-Host('-' * $(Get-Host).UI.RawUI.WindowSize.Width)"')Do Set "separator=%%A"
Echo Welcome to %~nx0
Echo %separator%
Pause

If you can work out the batch commands retrieve the columns value you could use the output from the MODE command;
MODE CON
C:\Users\gjp>mode con
Status for device CON:
----------------------
Lines: 9001
Columns: 120
Keyboard rate: 31
Keyboard delay: 1
Code page: 850

I would suggest you to use the following code:
#echo off
setlocal EnableDelayedExpansion
for /F "skip=4 tokens=2" %%A IN ('mode CON') do (
for /L %%B IN (1 1 %%A) do set "hyphen=!hyphen!-"
echo !hyphen!
goto :subroutine
)
:subroutine
echo You may continue here
pause
which is a bit complicated, but should do what you want.
The code searches for the columns in mode CON's command output and adds to hyphen variable these accordingly.

Related

List Directory and number of files with specific extension, build a specific menu

I am trying to create a menu with submenus which their names without extension come from the directory. However, I am unable to make a variable for choice as number. This code does not work anyhow. I would also want to display a number at the beginning of each file name in the menu; in fact, number of the files will also be one of the number that user selects as input. I could not overcome the problem.
#echo off
cd C:\Users\Murray\Documents\ConfigFiles\
for /f %%A in ('dir /a-d-s-h /b *conf ^| find /v /c ""') do set count=%%A
echo File count = %count%
for %%F in ("C:\Users\Murray\Documents\ConfigFiles\*.conf") do echo %%~nxF
set choice=
set /C /N="Please choice: "
if "%choice%" == "%count%" goto SUBMENU
if NOT EXIST "C:\Users\Murray\Documents\ConfigFiles\%choice%" goto NOFILE
:SUBMENU
Echo You are here
goto end
:NOFILE
echo %choice% could not be found.
goto END
:end
Any help will be appreciated.
Here's a quick example of a method touted in the answer by on no. It will print a number to the screen followed by the names of each file matching file extension, so will allow a large number of matching files, (although the end user may have to scroll a long list). Once a file is chosen, your end user then just types its corresponding number. The code should not proceed beyond the input request until a number matching one in the list is ENTERed.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "src=C:\Users\Murray\Documents\ConfigFiles"
Set "ext=.config"
If Not Exist "%src%\*%ext%" Echo No file matches.& GoTo End
For /F "Delims==" %%G In ('"(Set #) 2>NUL"') Do Set "%%G="
For /F "Delims==" %%G In ('%SystemRoot%\System32\wbem\WMIC.exe OS Call /? ^|
%SystemRoot%\System32\find.exe "=="') Do Set "HT=%%G"
For /F "Tokens=1* Delims=:" %%G In ('Dir /B /A:-D "%src%\*%ext%" 2^>NUL ^|
%SystemRoot%\System32\findstr.exe /E /I /L /N "%ext%"'
) Do Set "#%%G=%%H" & Echo( %%G.%HT:~-1%%%H
If Not Defined #1 Echo No file matches.& GoTo End
:Opt
Echo(
Set "HT=" & Set "opt="
Set /P "opt=Enter the number for your chosen file>"
If Not Defined opt (GoTo Opt) Else Set "opt=%opt:"=%"
Set # | %SystemRoot%\System32\findstr.exe /B /L "#%opt%=" 1>NUL || GoTo Opt
SetLocal EnableDelayedExpansion
For %%G In ("!#%opt%!") Do EndLocal & Set "opt=%%~G"
#Rem Your code goes below here
Echo(& Echo You Selected %opt%
#Rem Your code ends above here
:End
Setlocal EnableDelayedExpansion & For /F "Tokens=1,2" %%G In ("!CMDCMDLINE!"
) Do Endlocal & If /I "%%~nG" == "cmd" If /I "%%~H" == "/c" Echo(& Echo Press^
any key to exit.&Pause 1>NUL
All you need to do is to modify the variables values on lines 4 and 5, if necessary, in order to test it. I will not be supporting changes or additions beyond that. Once you have tested the code, you may insert your code between lines 25 and 29, replacing the example line I left there for your test.
Batch's limitations are to blame for sub-par corrections to this question.
Here's the best I could whip up in a few seconds:
#echo off
:one
cls
cd C:\Users\Murray\Documents\ConfigFiles\
for %%F in ("C:\Users\Murray\Documents\ConfigFiles\*.conf") do echo %%~nxF
echo.
echo Enter Configuration Name:
set/p "prompt=>"
if exist %prompt%.txt goto :two
if exist %prompt% goto :two
cls
echo File not found
pause >NUL
goto :one
:two
cls
REM When file is found, this code will run
pause >NUL
The set command does not prompt for user input unless specified with the /p switch. To make your code more friendly, i'd also recommend to prompt for the filepath earlier on in the code.
EDIT: A few alternative solutions: Declare the 9th option of the prompt of the choice command as a "second page" or "more" option. This would really be a pain for the user in a directory with tens or hundreds of files. Another; you can assign an integer to each file that matches your quasi-query and echo them before each filename on the screen, then allow the user to input the number to get that file. That seems fairly efficient, and if you'd like to explore one or both of those alternates I can help (if you need it).

Batch .txt reader

So, basically I want a Batch file to read a .txt. The problem is that the Batch file needs to update everytime a new line gets written to the .txt
#echo off
set "pc=%1"
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen=%%A"
type %pc%
set /A zeilen1=%zeilen%
:loop
if not %zeilen% == %zeilen1% (
set "line="
set zeilen2=%zeilen% - 1
for /f %%a in ('more/e +%zeilen2% ^< %pc%') do (
if not defined line set "line=%%a"
)
echo %line%
set /A zeilen+=1
)
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen1=%%A
goto loop
I also can't use the type command (line 9-13) because I don't want to refresh the whole .txt only the last line.
sry for my poor english
Thanks
To start the Batch you need to do something like this call batch.cmd txtname.txt
A basic tail command can be written like so. Credit to #dbenham for his initial solution on DosTips.com
#echo off
call :Loop <"tailme.txt"
exit
:Loop
set "line="
set /p "line="
if defined line (
echo %line%
) else (
pathping -q 1 -p 300 localhost >nul
)
goto :loop
If you don't wish to use third party options and wish to keep it pure batch, it is very possible. From your question, it sounds like you wish to read the last line of a text file and have it update that text each time the text file is edited. Further more, this batch file much be call'ed to when it needs to be used.
To do this, we can compare the date it was last modified using forfiles in an for loop. The reason for this is that if we use the file properties EX: ECHO Last-Modified Date : %%~ta we will not get the properties down to seconds. Thus the file will only compare down to the minutes.
Now that we can grab the last modified properties we can use an IF statement to look for when the file get a new time stamp. From there we can use a modified script that reads only the last line of a text file (Configurable by set /a LINES=LINES+1 LINES+1 - Infin) made by #Patrick Cuff
To call this batch file you will want to use call ReadFile.bat txtname.txt
Call - Command
ReadFile.bat - Name of batch script
txtname.txt - Name of textfile to read
Bellow is the full script.
ReadFile.bat
#ECHO OFF
#GOTO READ
:LOOP
Rem | Look for changes
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeCurrent=%%a)
IF "%FileTimeLoad%"=="%FileTimeCurrent%" (goto LOOP) else (goto READ)
:READ
cls
Rem | Get current date
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeLoad=%%a)
Rem | Get the number of lines in the file
set LINES=0
for /f "delims==" %%I in (%1) do (
set /a LINES=LINES+1
)
Rem | Print the last line
set /a LINES=LINES-1
more +%LINES% < %1
goto LOOP
For help on any of the commands do the following:
call /?
set /?
for /?
if /?
So on.

Batch File: Assign random line of text file as variable for later use

I'm trying to write a very simple batch file for personal use...It's complete except for one thing I'm stumped on. Hopefully this is an easy fix (I'm effectively illiterate when it comes to code).
Basically what I'm trying to do is have the script choose a random line from a text file, do this a couple times with a couple different text files, then I wish to assign the output from each text file to a variable so that I can easily use them in various combinations...then repeat the process.
Here is what I have right now...
#ECHO OFF
:START
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A list1random=(%RANDOM% %% %NumLines%)
IF "%list1random%"=="0" (SET "list1random=") ELSE (SET "list1random=skip=%list1random%")
FOR /F "usebackq tokens=* %list1random% delims=" %%A IN (`TYPE %list1%`) DO (
>> output.txt ECHO %%A
)
:Finish
ENDLOCAL
GOTO START`
This procures the random line, and spits it to a text file. All is well, next step, take that random result and assign it to a variable...
#ECHO OFF
:START
SETLOCAL
SETLOCAL EnableDelayedExpansion EnableExtensions
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A list1random=(%RANDOM% %% %NumLines%)
IF "%list1random%"=="0" (SET "list1random=") ELSE (SET "list1random=skip=%list1random%")
FOR /F "usebackq tokens=* %list1random% delims=" %%A IN (`TYPE %list1%`) DO (
SET output1=%%A
)
>> output.txt ECHO %output1%
:Finish
ENDLOCAL
GOTO START
Now the output ceases to be random...instead it is always the last line of the referenced text file.
EDIT: The site suggested another question that was similar to mine. However, that person was having trouble getting the script to choose a valid line. I get a valid line every time, and a random one too (when I check it via echo), but a non-random line when proceeding on, assigning the output to a variable. I don't understand because it seems like a post-facto derandomization. I.E. the difference between the two scripts has nothing to do with procuring the random result, only what to do with that result AFTER it has it, right?
I appreciate any help in advance, this is the last step before I know everything I need to finish this, I'm excited!
Sorry, you're right...anyways, I figured out a simple workaround, probably not the quickest in terms of processing time, but whatever. Basically allow the initial part of the script to spit out the random result to a text file (as seemed to work just fine) then reference the text file as a variable.
#ECHO OFF
:START
SET "list1=list1.txt"
FOR /f %%a IN ('type "%list1%"^|find /c /v ""') DO SET /a numlines=%%a
SET /A listchoice=(%RANDOM% %% %NumLines%)
IF "%listchoice%"=="0" (SET "listchoice=") ELSE (SET "listchoice=skip=%listchoice%")
FOR /F "usebackq tokens=* %listchoice% delims=" %%A IN (`TYPE %list1%`) DO (
>> listoutput.txt ECHO %%A
)
Set /p list=<listoutput.txt
>> result.txt ECHO %list%
:Finish
DEL listoutput.txt
GOTO START
This is easy to do in PowerShell using the built-in Get-Random cmdlet.
$line = (Get-Content file.txt | where { $_ } | Get-Random)
Which makes it also easy in batch.
set filename=file.txt
for /f "tokens=*" %%a in ('powershell -ex bypass -c "gc %filename% | ? { $_ } | Get-Random"') do (
set "var=%%a"
)
The where { $_ } clause is only necessary to filter out any blank lines. You can omit it if you know your file has none.

Reading a specific column from a row using a batch file

I have a notepad which looks like this.
Job Name Last Start Last End ST Run/Ntry Pri/Xit
________________________________________________________________ ____________________ ____________________ __ ________ _______
DEV_xxx_xxx_xxx_xxxx_b 11/20/2012 22:05:00 ----- RU 9229277/1
This value "22:05:00" is present on the 77th column of row 3. Is there a way using a batch script that i can extract only this value and assign it to a variable. The above notepad is the redicrected output of an autosys command (if it helps)
I've been breaking my head for the past 3 days but to no avail.
Untested
#echo off
for /f "skip=2 delims=" %%a in (file.txt) do set "var=%%a"&goto :done
:done
set "var=%var:~76,8%"
echo "%var%"
pause
Another way (faster) to read the 3rd line.
#echo off
<file.txt (
set/p=
set/p=
set /p var=
)
set "var=%var:~76,8%"
Use a FOR /L loop if you want to skip a larger number of lines
#echo off
<file.txt (
for /l %%N in (1 1 2) do set/p=
set /p var=
)
set "var=%var:~76,8%"
If the job name never contains spaces, then it looks like you could also use FOR /F in the traditional way.
#echo off
for /f "skip=2 tokens=3" %%A in (file.txt) do set "var=%%A" & goto :break
:break
search it with GNU sed (very fast!)
for /f %%i in ('sed -n "/DEV/ {s/.*\([0-2][0-4]:[0-5][0-9]:[0-5][0-9]\).*/\1/p;q}" file.txt') do set "var=%%i"
echo %var%

Batch script .exe delete selection

There is a folder which contains some random files:
file1.txt
file2.exe
file3.cpp
file4.exe
How to SIMPLY display exe files connected with numbers like this:
1. file2.exe
2. file4.exe
And then I enter the number of the file, which I want to delete.. If it is even possible to do this simply..
Shortest bullet proof solution I can come up with. Like Anders, the DEL statement is disabled by the ECHO command. Remove the ECHO to make the menu functional.
#echo off
setlocal disableDelayedExpansion
for /f "delims==" %%A in ('set menu 2^>nul') do set "%%A="
for /f "tokens=1* delims=:" %%A in ('dir /b *.exe 2^>nul ^| findstr /n "^"') do (
set menu%%A=%%B
echo %%A. %%B
)
if not defined menu1 exit /b
set "delNum="
set /p "delNum=Delete which file (enter the number): "
setlocal enableDelayedExpansion
if defined menu!delNum! echo del "!menu%delNum%!"
The only thing I can think of that could go wrong is part of the menu could scroll off the screen if there are too many entries.
Additional messages can easily be incorporated. and an ELSE condition could be appended to the input validation to deal with invalid input.
A few subtle points of the code:
FINDSTR /N provides incrementing file number. Avoids need for delayed expansion or CALL within menu builder loop. Delayed expansion should not be enabled when expanding a FOR variable containing a file name because it will corrupt names containing !.
: is a safe FOR delimiter because a file name cannot contain :.
delNum is cleared prior to SET /P because SET /P will preserve existing value if <Enter> is pressed without entering anything.
Checking for the existence of the variable is the simplest way to validate the input. This is why it is critical that any existing MENU variables are undefined prior to building the menu.
Must use delayed expansion in IF DEFINED validation, otherwise space in input could crash the script (thanks Anders for pointing out the flaw in the original code)
DEL target must be quoted in case it contains spaces, even when delayed expansion is used.
Added test to make sure at least one menu entry exists before continuing. There may not be any .exe files left to delete.
#echo off
setlocal EnableDelayedExpansion
set i=0
for %%f in (*.exe) do (
set /A i+=1
set file[!i!]=%%f
echo !i!. %%f
)
set i=0
set /P i=File to delete:
del !file[%i%]!
Not exactly pretty but it gets the job done
#echo off
setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
goto main
:addit
set /A end=end + 1
set %end%=%~1
echo %end%. %~1
goto :EOF
:main
set end=0
for %%A in ("*.exe") do (
call :addit "%%~A"
)
if "%end%"=="0" goto :EOF
echo.&set idx=
set /P idx=Delete (1...%end%)
if not "%idx"=="" if %idx% GEQ 1 if %idx% LEQ %end% (
for /F "tokens=1,* delims==" %%A in ('set %idx% 2^>nul') do (
if "%idx%"=="%%~A" (
echo.Deleting %%~B...
rem del "%%~B"
)
)
)

Resources