Home > Net >  Batch file: Where is the phantom line break coming from in this code?
Batch file: Where is the phantom line break coming from in this code?

Time:12-14

I am trying to append a backslash to the end of a string (a folder name), and instead of getting a backslash, I seem to be getting a line break, 13 spaces, then finally the backslash. Where is this coming from?

Here is the code I wrote:

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION

:: After the user chooses a folder from a menu, the choice is stored in ChosenFolder
:: A typical value for ChosenFolder would be "3 .\Folder1"

set "ParentFolder=!ChosenFolder:~2!^\"
echo ParentFolder is !ParentFolder!

The output I get is:

ParentFolder is .\Folder1
             \

If I just manually set the ChosenFolder variable to "3 .\Folder", this error doesn't happen, so here is the code that ultimately generates the faulty value of ChosenFolder (a slightly modified version of Magoo's code that answered this question, bless his heart!)

SET "choicenames=z0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"

:: remove variables starting #
FOR /F "delims==" %%e In ('set # 2^>Nul') DO SET "%%e="
FOR /L %%e IN (1,1,%pagewidth%) DO SET "#spaces=!#spaces! "

:: Read dirnames to #nn, count to #entries

FOR /d %%e IN ("%~1\*.") DO SET /a #entries =1&SET "#!#entries!=%%e"
SET /a #entries =1&SET "#!#entries!=z Quit."
SET /a #columns=(#entries   pagesize - 1) / pagesize
SET /a #rows=(#entries   #columns - 1)/#columns
SET /a #columnwidth=(pagewidth/#columns) - 3
SET "#choices=z"

FOR /L %%e IN (1,1,%#entries%) DO (
 rem column contents - max length   terminal spaces 
 IF %%e neq %#entries% (
  SET "#%%e=!#%%e:~-%#columnwidth%!%#spaces%"
  SET "#%%e=!choicenames:~%%e,1! !#%%e:~0,%#columnwidth%!"
  SET "#choices=!#choices!!choicenames:~%%e,1!"
 )
)

FOR /L %%e IN (1,1,%#rows%) DO (
 SET /a cols=%%e   %#rows% 
 SET /a #line=%%e   (%#rows% * 2^)
 SET "cols=!cols! !#line!"
 SET "#line=!#%%e!"
 FOR %%y IN (!cols!) DO IF DEFINED #%%y SET "#line=!#line! !#%%y!"
 ECHO !#line!
)

IF %#entries% gtr 36 (
 choice /cs /c %#choices%
) ELSE (
 choice /c %#choices%
)

IF ERRORLEVEL 2 (
 ECHO ERRORLEVEL is %ERRORLEVEL%
 SET /a #choices=%ERRORLEVEL%-1
 CALL SET "ChosenFolder=%%#!#choices!%%"
 ECHO choice made : !ChosenFolder:~2!
 CHOICE /C snc /N /M "(S)elect, (N)avigate or (C)ancel? "
 IF errorlevel 3 goto begin
 IF errorlevel 2 CALL :SelectFolder !ChosenFolder:~2!
 IF errorlevel 1 EXIT /B 0
) ELSE GOTO begin

CodePudding user response:

#? contains the name as, eg : 3 u:\Folder1 . The spaces are added to lay out the menu appropriately, so they would need to be deleted (hence the series of spaces when manipulated and the need to lop off the leading 2 characters).

\ does not need to be escaped if simply appended to the string.

Note however - Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.

FOR /d %%e IN ("%~1\*.") DO SET /a #entries =1&SET "#!#entries!=%%e"&SET "#originalnames!#entries!=%%e"

To establish a parallel list of names, #originalnames?.


IF ERRORLEVEL 2 (
 ECHO ERRORLEVEL is %ERRORLEVEL%
 SET /a #choices=%ERRORLEVEL%-1
 CALL SET "ChosenFolder=%%#originalnames!#choices!%%"
 ECHO choice made : !ChosenFolder!
 CHOICE /C snc /N /M "(S)elect, (N)avigate or (C)ancel? "
 IF errorlevel 3 goto begin
 IF errorlevel 2 CALL :SelectFolder
rem IF errorlevel 1 EXIT /B 0
) ELSE GOTO begin

GOTO :EOF

:selectfolder

ECHO  %chosenfolder% 

FOR /f "delims=" %%e in ("%chosenfolder%") do SET "Parentfolder=%%~dpe"
echo ParentFolder of %chosenfolder% is  %ParentFolder% 

GOTO :eof

(Note on either end of the names to show absence of spaces.)

This assigns the original name (not the displayed name which may have been truncated) to chosenfolder.

Since chosenfolder is not within (...) (ie. a code block) you can use %chosenfolder% to access its contents. !chosenfolder! will also work, but it implies that the value of chosenfolder may vary because it's within a code block - but within the subroutine :SelectFolder there are no code blocks.

chosenfolder is of the form u:\folder 1. so the for assigns this to %%e and the parser then interprets u:\folder 1 as drive=u:, path=\ and filename=folder 1

  • Related