Why doesn't this batch script work? Reading lines from file - windows

ok, I give up. Why doesn't this work?
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
FOR /F %%I in (myfile.txt) do (
echo I: %%i
set LINE=%%i
echo LINE: %LINE%
)
"echo I:" displays the lines correctly, but "echo LINE:" is empty
I have tried different variations with the same results, such as
set LINE=%i
set LINE=%i%
set LINE=!i!
Obviously there is something simple I am not understanding.

you enabled delayed expansion, so the only thing you have to do is: use it.
replace echo LINE: %LINE% with echo LINE: !LINE!
EDIT: solution without delayed extension
FOR /F %%I in (myfile.txt) do ( call DoIt %%I )
exit /b
:DoIt
echo I: %1
set LINE=%1
echo LINE: %LINE%
goto :eof

Related

Win Batch: Help defining variable in a FOR loop

I made this script that finds all directories and echoes the directorie's name to a .txt file. The script is working but it ends up echoing only %A without any value. My script is below!
set /a count=0
setlocal EnableDelayedExtensions
FOR /D %%A in ("*") DO (call :sub)
endlocal
pause
exit
:sub
(echo [DIR] %%A)>>%count%.txt
set /a count+=1
The output in the .txt files is [DIR] %A.
Any idea how to fixe this? Thanks -David
First remark, you are using an invalid option for setlocal but that is probably just a typo.
The problem is that you are try to use a for-parameter where it cannot be used.
The rule is "A for-parameter can only be used within the command or command block () of a for loop"
Your subroutine is not within the command block of a for loop, but you can start a dummy for loop in the subroutine which will give you access to all available for-parameters.
set /a count=0
setlocal EnableDelayedExpansion
FOR /D %%A in ("*") DO (call :sub)
endlocal
pause
exit/b
:sub
For %%. in (.) do (echo [DIR] %%A)>>%count%.txt
set /a count+=1
You need to pass the parameter to the subroutine.
From https://www.informit.com/articles/article.aspx?p=1154761&seqNum=11 :
for %%f in (*.dat) do call :onefile %%f
exit /b
:onefile
echo Processing file %1...
echo ... commands go here ...
exit /b
As you've already enabled delayed expansion, there's no need to use a Call to a label, just do it within the loop.
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
Set "count=0"
For /D %%G In (*) Do (
Set /A count += 1
(Echo [DIR] %%G) 1>"!count!.txt"
)
On this version, I've started at 1 instead of 0 for the first text file name, if you really want to start at 0, change line 3 to Set "count=-1"

Echo first three characters of filenames in CMD Windows

for /r %g in (*.html) do echo %~ng:~0,3%
This does not work. I have tested a lot, but could not find the answer.
How do you echo the first three characters of all HTML-filenames?
#ECHO OFF
SETLOCAL
:: first way:
FOR /r %%g IN (*.html) DO (
SET "var=%%~ng"
CALL ECHO %%var:~0,3%%
)
pause
:: second way:
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /r %%g IN (*.html) DO (
SET "var=%%~ng"
ECHO !var:~0,3!
)
GOTO :EOF
The fundamental issue is that substringing must be applied to an ordinary environment variable, not to a metavariable.

Windows cmd: echo without new line but with CR

I would like to write on the same line inside a loop in a windows batch file.
For example:
setlocal EnableDelayedExpansion
set file_number=0
for %%f in (*) do (
set /a file_number+=1
echo working on file number !file_number!
something.exe %%f
)
setlocal DisableDelayedExpansion
This will result in:
echo working on file number 1
echo working on file number 2
echo working on file number 3
.
.
.
I would like all of them to be on the same line.
I found a hack to remove the new line (e.g. here: Windows batch: echo without new line), but this will produce one long line.
Thanks!
#echo off
setlocal enableextensions enabledelayedexpansion
for /f %%a in ('copy "%~f0" nul /z') do set "CR=%%a"
set "count=0"
for %%a in (*) do (
set /a "count+=1"
<nul set /p ".=working on file !count! !CR!"
)
The first for command executes a copy operation that leaves a carriage return character inside the variable.
Now, in the file loop, each line is echoed using a <nul set /p that will output the prompt string without a line feed and without waiting for the input (we are reading from nul). But inside the data echoed, we include the carriage return previously obtained.
BUT for it to work, the CR variable needs to be echoed with delayed expansion. Otherwise it will not work.
If for some reason you need to disable delayed expansion, this can be done without the CR variable using the for command replaceable parameter
#echo off
setlocal enableextensions disabledelayedexpansion
for /f %%a in ('copy "%~f0" nul /z') do (
for /l %%b in (0 1 1000) do (
<nul set /p ".=This is the line %%b%%a"
)
)
Thanks to the answer of MC ND I have a created a subroutine, echocr, that you can call without
delayed expansion, that will echo a string with only a carriage return,
and no newline. (The spaces after %input% are adjusted to cover all previous messages).
You can use it to overwrite a line as shown in the modified
code:
#echo off
call :echocr "good morning"
PING -n 2 127.0.0.1>nul
call :echocr "good afternoon"
PING -n 2 127.0.0.1>nul
call :echocr "bye now"
PING -n 2 127.0.0.1>nul
pause
:echocr
:: (echo string with carriage return, no line feed)
for /F "tokens=1 delims=# " %%a in (
'"prompt #$H# & echo on & for %%b in (1) do rem"'
) do set "backspace=%%a"
set input=%~1
set "spaces40= "
set "spaces120=%spaces40%%spaces40%%spaces40%
for /f %%a in ('copy "%~f0" nul /z') do (
set /p ".=*%backspace%%spaces120%%%a" <nul
set /p ".=*%backspace%%input%%%a" <nul
)
exit /b
The above no longer works in Windows 7 and later.
I found the reason is delayed expansion that should be set after ASCII_13 assignment, maybe someone smart could explain why exactly.
Anyway, the code below works both on Windows 7 and Windows 10.
#set licz=0
#setlocal
#for /f %%a in ('copy /Z "%~dpf0" nul') do #set "ASCII_13=%%a"
#setlocal enabledelayedexpansion
:loop
#set /a licz=licz+1
#set /p "=Waiting time: %licz% seconds!ASCII_13!" <NUL
#Timeout /T 1 /Nobreak > NUL
#GOTO loop
If you do not like the cursor blinking at beginning of the line, transfer ASCII_13 to the beginning to execute CR before text.
Needs to be preceeded by any ASCII character, though, to avoid getting stripped. And this will be visible as the last char on the line, so be wary here :)
#set /p "=.!ASCII_13!Waiting time: %licz% seconds" <NUL
#echo off
setlocal enableextensions enabledelayedexpansion
Rem Get a carriage return character
set "CR=" & for /f %%a in ('copy /Z "%~f0" nul') do if not defined CR set "CR=%%a"
rem The progress bar
set "fill=[###################]"
echo(
rem For each character in the fill
for /l %%a in (2 3 21) do (
rem Calculate the right part of the bar
set "spaces=!fill:~%%a!"
rem Output the left and right parts of the bar and carriage return
<nul set/p ".=:: Please Connect Device : !fill:~0,%%a!!spaces:#= !!CR!"
rem Pause for a second
ping -n 2 "" > nul
)
echo(

For Loop in Batch File Renames One File Twice

I wrote this batch file to append some text to the filenames of a set of jpeg files, giving the option to append them before or after the current filename.
But for some odd reason when appending before the filename, one file is being proccessed twice getting the result as new_new_FileName.jpg while all other files are getting just new_FileName.jpg.
Interesting enough, this problem isn't happening always, as well as when appending after the filename it is always working fine.
Following is the entire code, with no visual difference between the before or after, but still resulting differently. Can anyone please examine this file and explain me where I'm wrong?
Help is appreciated.
#ECHO off
title Rename Script
set /A count=1
:Start
cls
set /p STR=choose a string to append:
cls
echo 1. Append before
echo 2. Append after
set /p choice=I choose (1,2):
if %choice%==1 goto renameb
if %choice%==2 goto renamea
:renameB
cls
echo Appending '%STR%' before current file name.
echo.
set /A count=0
FOR %%a in (*.jpg) DO (
ren "%%~a" "%STR%%%~na%%~xa"
echo Was: %%~a Became: %STR%%%~na%%~xa
set /A count+=1
)
goto end
:renameA
cls
echo Appending '%STR%' after current file name.
echo.
set /A count=0
FOR %%a in (*.jpg) DO (
ren "%%~a" "%%~na%STR%%%~xa"
echo Was: %%~a Became: %%~na%STR%%%~xa
set /A count+=1
)
goto end
:end
echo[
echo %count% files were renamed.
echo[
echo The process in now done.
pause
for renaming, the simple for loop doesn't work:
FOR %%a in (*.jpg) DO (
for some reasons from the old CP/M days with the FCB's a for /f loop is needed:
for /f "delims=" %%a in ('dir /a-d /b *.jpg') do (

Windows CMD FOR loop

I'm trying to make a code which will get first words from all lines of HELP's output to a variable and echo this variable. Here is my code:
#echo off
set a=
for /F "tokens=1,*" %%i in ('help') do (
set a=%a% %%i
)
echo %a%
But it returns first word from only last line. Why?
Bali C solved your problem as stated, but it looks to me like you are trying to get a list of commands found in HELP.
Some of the commands appear on multiple lines, so you get some extraneous words. Also there is a leading and trailing line beginning with "For" on an English machine that is not wanted.
Here is a short script for an English machine that will build a list of commands. The FINDSTR command will have to change for different languages.
#echo off
setlocal enableDelayedExpansion
set "cmds="
for /f "eol= delims=." %%A in ('help^|findstr /bv "For"') do (
for /f %%B in ("%%A") do set "cmds=!cmds! %%B"
)
set "cmds=%cmds:~1%"
echo %cmds%
EDIT
Ansgar Wiechers came up with a more efficient algorithm to extract just the command names at https://stackoverflow.com/a/12733642/1012053 that I believe should work with all languages. I've used his idea to simplify the code below.
#echo off
setlocal enableDelayedExpansion
set "cmds="
for /f %%A in ('help^|findstr /brc:"[A-Z][A-Z]* "') do set "cmds=!cmds! %%A"
set "cmds=%cmds:~1%"
echo %cmds%
You need to use delayed expansion in your for loop
#echo off
setlocal enabledelayedexpansion
set a=
for /F "tokens=1,*" %%i in ('help') do (
set a=!a! %%i
)
echo %a%
Instead of using %'s around the a variable, you use !'s to use delayed expansion.
Because the echo is outside the do ( ...... )
#echo off
for /F "tokens=1,*" %%i in ('help') do (
echo %%i
)
and no need to print a, you can use directly %%i.
Another very simple example could be a batch like this saved as help1.cmd
#echo off
for /F "tokens=1,*" %%i in ('help') do (
if /I "%%i" EQU "%1" echo %%j
)
and you call this batch like
help1 MKDIR
to get the short help text for the MKDIR command

Resources