简体   繁体   中英

Writing to different lines with Batch

I'm trying to make a reminder system within batch in which there are different lines of reminders. My batch program will write to different lines in a .txt file, but it isn't working. Could you please help and try to find the issues?

@echo off
echo Enter slot # for reminder
set /p n=
cls
echo Please type in the assignment name
set /p a=
echo ----------------------------------
echo Please type in the class
set /p c=
echo ----------------------------------
echo Please type in the date due
set /p d=
cls
if %n%==1 goto l1
if %n%==2 goto l2
if %n%==3 goto l3
if %n%==4 goto l4
if %n%==5 goto l5
if %n%==6 goto l6
:l1
echo Reminder for %c% Homework! %a%,%d% > Reminder.txt
:end

:l2
echo Reminder for %c% Homework! %a%,%d% >> Reminder.txt
:end

:l3
echo Reminder for %c% Homework! %a%,%d% >>> Reminder.txt
:end

:l4
echo Reminder for %c% Homework! %a%,%d% >>>> Reminder.txt
:end

:l5
echo Reminder for %c% Homework! %a%,%d% >>>>> Reminder.txt
:end

:l6
echo Reminder for %c% Homework! %a%,%d% >>>>>> Reminder.txt
:end

Hints to fix what you've got:

  • The > character won't let you write to specific lines, and there's no native support in Windows batch to do such a thing.
  • There are two operators that use the > character:
    > , which redirects output to a file (replacing any existing content),
    and
    >> , which appends (adds to the end of) a file.
  • You've got multiple instances of :end , but that's invalid. :end is a label, which is a unique reference to that point in the code. When you add more than one, some get ignored and you get undefined behaviors, which is bad.
  • It looks like you're trying to use :end to exit. Use goto :EOF for that. It jumps to the built-in label :EOF , short for End Of File.
  • You need to handle the case where n is none of the predefined values. Currently if someone entered 7 for n , your program would get to the logic after :l1 and run it, which is wrong. Put a goto :EOF there just in case.


How to approach solving this type of issue with batch:
The only way I can think of off the top of my head to modify a specific line is to iterate through all lines using a for /f loop, rewriting each line (to a temporary file) until you encounter the one you want to change, then write your new content instead of the existing content. Then when you're done iterating, you can replace the original file with that temporary file.
You would have to do this each time you wanted to change a new line. Batch is a really simple language that doesn't have useful constructs like arrays, or the many external tools that a shell scripting language like Bash would have. It's also got some really unsophisticated runtime evaluation.

Here's a partial solution that you can combine with a few lines from your code above to achieve what you want. It prompts you for a line number, then puts the content of the newContent variable (replace with your implementation) into the file at the specified line:

REM suppresses the echo of the commands in the program
@ECHO OFF
REM sets a feature that overcomes some of the weak runtime evaluation limitations that batch has
setlocal ENABLEDELAYEDEXPANSION
REM The name of your file
set fname=file.txt
REM If our file doesn't already exist, make a new one with 6 empty lines since that's all we want for now.
if EXIST "%fname%" goto alreadyExists
for /l %%b in (1,1,6) do echo.>>"%fname%"
:alreadyExists
REM The name of a temp file
set tfile=f2.txt
REM A counter to track the line number
set counter=0
REM Input to get the line number you wish to replace
set /p replacementLine=Type the line number that should be replaced:
REM The content that goes on the replaced line
set newContent=New entry
REM Read the file, iterate through all lines.
for /f "tokens=*" %%a in (file.txt) do (
REM Add one to the counter
set /a counter=!counter!+1
REM Use the redirect '>' operator for the first line
if "!counter!"=="1" (

if "!counter!"=="%replacementLine%" (
REM We're on the line we wish to replace, so use the replacement line content
echo.%newContent% >f2.txt
) else (
REM We're NOT on the line we wish to replace, so use the original line content
echo.%%a >f2.txt
)
) else (
REM else for lines other than the first, use the append redirect '>>'
if "!counter!"=="%replacementLine%" (
REM We're on the line we wish to replace, so use the replacement line content
echo.%newContent% >>f2.txt
) else (
REM We're NOT on the line we wish to replace, so use the original line content
echo.%%a >>f2.txt
)
)
)
REM Delete the original file
del "%fname%"
REM Replace it with the modified copy
ren "%tfile%" "%fname%"

You can replace a few lines at the top get the functionality you want.

you can't write to a specific line in a file with batch. Instead you have to rewrite the complete file.

Steps: a) read the file. b) change the desired line. c) (over)write the file with the new data.

@echo off
setlocal enabledelayedexpansion
if not exist reminder.txt call :InitFile    :: create the file, if it doesn't exist
set /p "n=Enter slot # for reminder: "
set /p "a=type in the assignment name: "
set /p "c=type in the class: "
set /p "d=type in the date due: "
cls

call :ReadFile   
set "_Line[%n%]=Reminder for %c% Homework: %a%,%d%" 
call :WriteFile  
type Reminder.txt
goto :eof

:ReadFile
set x=0
for /f "delims=" %%i in (reminder.txt) do (
  set /a x+=1
  set "_Line[!x!]=%%i"
)
goto :eof

:WriteFile
set x=0
(for /f "tokens=2 delims==" %%i in ('set _Line[') do echo %%i)>Reminder.txt
goto :eof

:InitFile
(for /l %%i in (1,1,6) do echo Reminder %%i [empty])>Reminder.txt
goto :eof

(Note: this would make trouble with more than 9 lines because of the alphabetical sorting with set _line[ , but as you need only 6 lines, this should not be a problem for you)

Note: your input shouldn't contain !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM