how to use :Format function effectively

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
maphew
Posts: 6
Joined: 05 Feb 2012 15:41

how to use :Format function effectively

#1 Post by maphew » 05 Feb 2012 15:56

Hi, I've just discovered dostips.com for the first time. I've been bashing away at batch files for years, with some success here and there, and am bemused that I've never stumbled across this excellent resource before. Thanks so much for sharing your knowledge, I've learned a lot in the last hour. ;-)

Now to the issue of the moment: How might I use the :Format function published on this website effectively? When I pass it a string which contains more items than the number of columns in the

Code: Select all

Fmt
argument the remaining items are silently discarded.

For example this batch file will only display the first 3 of "alcrmv alcupd bfsvc explorer fveupdate HelpPane hh HideWin InstFunc IsUninst notepad regedit SOUNDMAN twunk_16 twunk_32 winhelp winhlp32 write"

Code: Select all

:showWinExe
  setlocal enabledelayedexpansion
  pushd %windir%
  for %%g in (*.exe) do set .exe=!.exe! %%~ng
  call :Format [-15][-15][-15] %.exe%
  popd
  goto :eof

Result:

Code: Select all

         alcrmv         alcupd          bfsvc


Desired result:

Code: Select all

         alcrmv         alcupd          bfsvc
       explorer      fveupdate       HelpPane
       HelpPane             hh        HideWin
etc...

alan_b
Expert
Posts: 357
Joined: 04 Oct 2008 09:49

Re: how to use :Format function effectively

#2 Post by alan_b » 06 Feb 2012 03:26

Perhaps there are weird consequences when using a weird variable starting with a dot such as .exe
It certainly is confusing to mere mortals like me :)

Near the top of each page you can login / logout.
Just to the left is "Search"
I have just pasted into that
:Format
It gives me 276 results.
The first result does not help - it is your post,
but there are 275 others which may show how it is used.

maphew
Posts: 6
Joined: 05 Feb 2012 15:41

Re: how to use :Format function effectively

#3 Post by maphew » 06 Feb 2012 18:53

Hi Alan, thanks for the response.

It's not the variable name, I've tried others with no difference, the remaining items are still discarded. (For what it's worth, I use dot as variable prefix in preference to underscore because it's easier to type.) I have also been searching ':Format', and 'columns', and reading the resultant threads but have not come across the solution. (Not come across yet that is, I'm still reading. And many of those 275+ results having nothing to do with the :Format function as regular ol' format matches as well).

alan_b
Expert
Posts: 357
Joined: 04 Oct 2008 09:49

Re: how to use :Format function effectively

#4 Post by alan_b » 07 Feb 2012 02:33

Perhaps you are using illegal arguments for the format string
you have 3 negative numbers, each -15
the code suggests starting with negative 10 and then two positive tens.

Why not try [-15] [15] [15] [15]
That might show if the problem is when moving from the first line to the second,
or if there is something "wild and wacky" about what happens with the fourth item, "explorer",
e.g. could there be permissions issues when trying to use :Format to extract information about Explorer.exe ?

I believe this is the code you are using,
into which I have inserted a debug suggestion
"REM INSERT SOME DEBUG HERE e.g. ECHO a = "%%a" : b = "%%b""
that might help you see what strings are being processed.

Code: Select all

:Format fmt str1 str2 ... -- outputs columns of strings right or left aligned
::                        -- fmt [in] - format string specifying column width and alignment, i.e. "[-10][10][10]"
:$created 20060101 :$changed 20091130 :$categories Echo
:$source http://www.dostips.com
SETLOCAL
set "fmt=%~1"
set "line="
set "spac=                                                     "
set "i=1"
for /f "tokens=1,2 delims=[" %%a in ('"echo..%fmt:]=&echo..%"') do (
REM INSERT SOME DEBUG HERE  e.g. ECHO a = "[%%a]" : b = "[%%b]"
    set /a i+=1
    call call set "subst=%%%%~%%i%%%spac%%%%%~%%i%%"
    if %%b0 GEQ 0 (call set "subst=%%subst:~0,%%b%%"
    ) ELSE        (call set "subst=%%subst:~%%b%%")
    call set "const=%%a"
    call set "line=%%line%%%%const:~1%%%%subst%%"
)
echo.%line%
EXIT /b


Alan

maphew
Posts: 6
Joined: 05 Feb 2012 15:41

Re: how to use :Format function effectively

#5 Post by maphew » 09 Feb 2012 15:07

Hi Alan, I appreciate your willingness to help troubleshoot this, thanks :)

I played with and without negatives for the Fmt argument. The subsequent negative parameters push the columns to the right. Without them the output overposts each other. In all cases the results were still truncated. Likewise changing the pushd from %windir% to folder where it's guaranteed there are no permissions issue did not change the results.

Here is the full script and output. It quits after processing the first loop:

...

or rather the full script and output was supposed to be there but whenever I pressed save or submit I got a server reset error until I removed it.

maphew
Posts: 6
Joined: 05 Feb 2012 15:41

Re: how to use :Format function effectively

#6 Post by maphew » 09 Feb 2012 15:13

maphew wrote:Hi Alan, I appreciate your willingness to help troubleshoot this, thanks :)
or rather the full script and output was supposed to be there but whenever I pressed save or submit I got a server reset error until I removed it.


...so here it is on pastebin instead: http://pastebin.com/TSbJQ5sH

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: how to use :Format function effectively

#7 Post by foxidrive » 10 Feb 2012 03:43

With some testing it appears that the [-widthoffset] has to be specified for each term. See below.

It only seems to support 8 terms.

Code: Select all

@echo off

call :format [-3][-3][-3][-3][-3][-3][-3][-3] 1 2 3 4 5 6 7 8
pause
goto :eof

:Format fmt str1 str2 ... -- outputs columns of strings right or left aligned
::                        -- fmt [in] - format string specifying column width and alignment, i.e. "[-10][10][10]"
:$created 20060101 :$changed 20091130 :$categories Echo
:$source http://www.dostips.com
SETLOCAL
set "fmt=%~1"
set "line="
set "spac=                                                     "
set "i=1"
for /f "tokens=1,2 delims=[" %%a in ('"echo..%fmt:]=&echo..%"') do (
REM INSERT SOME DEBUG HERE  e.g. ECHO a = "[%%a]" : b = "[%%b]"
    set /a i+=1
    call call set "subst=%%%%~%%i%%%spac%%%%%~%%i%%"
    if %%b0 GEQ 0 (call set "subst=%%subst:~0,%%b%%"
    ) ELSE        (call set "subst=%%subst:~%%b%%")
    call set "const=%%a"
    call set "line=%%line%%%%const:~1%%%%subst%%"
)
echo.%line%
EXIT /b

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: how to use :Format function effectively

#8 Post by foxidrive » 10 Feb 2012 04:12

Modified code, new reply:

This is a similar routine but it allows more strings and uses a single formatting number which is applied to all the strings.
It doesn't do what the OP wants because it doesn't have the smarts to split lines into, say, three terms per line and the width of the dos window will dictate where the line break will occur.


Code: Select all

@echo off

call :format2 -10 abc def ghi jkl mno pqr stu vwx yz 10 20
pause
goto :eof

:Format2 [-]num str1 str2 ...
::          outputs columns of strings right or left aligned
::          num specifys column width and alignment
::         (negative num is right aligned, positive num is left aligned)
:$source http://www.dostips.com based on Format function
SETLOCAL
set "prepend="
set "append="
set "fmt=%~1"
:: rem 25 spaces
set "space=                         "
if %1 GEQ 0 call set "prepend=%%space:~0,%fmt%%%
if %1 LSS 0 call set "append=%%space:~%fmt%%%
:loop
shift
if not "%~1"=="" set "line=%line%%prepend%%~1%append%"
if not "%~2"=="" goto :loop
echo.%line%

alan_b
Expert
Posts: 357
Joined: 04 Oct 2008 09:49

Re: how to use :Format function effectively

#9 Post by alan_b » 10 Feb 2012 04:21

Sorry, I give up.

There are some clever tricks in :Format.

I only have enough skill to see they are clever, but do not understand how they work.

The only correction I can suggest to your pasted code is to make the very first line
@echo off & setlocal EnableDelayedExpansion & CLS

and to change one debug line from
ECHO Loop number: %i%
to
ECHO Loop number: !i!
That uses delayed expansion which required the very first line,
and shows the "now" value of a variable rather than the value upon entering a loop.

Then I could see the Loop number incrementing from 2 through to 5
instead of being stuck at 1

maphew
Posts: 6
Joined: 05 Feb 2012 15:41

Re: how to use :Format function effectively

#10 Post by maphew » 13 Feb 2012 11:52

foxidrive wrote:With some testing it appears that the [-widthoffset] has to be specified for each term. ... It only seems to support 8 terms.


Thanks for confirming that it's not just my system configuration or some kind of copy paste error. Also thanks for an idea of how to get closer to what I wanted.

I decided that trying to use this kind of text format in DOS/CMD is just not worth the effort for this project and took an alternate approach of using dir column output redirected to disk and parsing that to get rid of the bits I don't want.

Code: Select all

@echo off
setlocal enabledelayedexpansion
:Main
  rem Generate executables list
  pushd "%1"
  echo.                     > "%temp%\o-help-list.txt"
  dir /d *.exe |find ".exe" >>"%temp%\o-help-list.txt"
  echo.                     >>"%temp%\o-help-list.txt"
  dir /d *.bat |find ".bat" >>"%temp%\o-help-list.txt"
  popd

  rem Strip extensions and report just names
  rem c.f. http://ss64.com/nt/syntax-replace.html
  for /f "usebackq delims=?" %%g in ("%temp%\o-help-list.txt") do (
    set _s=%%g
    set _s=!_s:.exe=!
    set _s=!_s:.bat=!     
    echo.       !_s!
    )
  echo.
  del "%temp%\o-help-list.txt"
  goto :eof

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: how to use :Format function effectively

#11 Post by foxidrive » 13 Feb 2012 21:51

I didn't spend much time testing yours, but this seems to work the same.

Code: Select all

@echo off
  pushd "%1"
    for /f "delims=" %%a in ('dir /b /o:n *.exe *.bat') do (
    echo.       %%~na
    )
  popd
  pause



If you want the blank line between extensions then repeat the for loop twice:

Code: Select all

@echo off
  pushd "%1"
    for /f "delims=" %%a in ('dir /b /o:n *.exe') do (
    echo.       %%~na
    )
  echo.
    for /f "delims=" %%a in ('dir /b /o:n *.bat') do (
    echo.       %%~na
    )
  popd
  pause



Or this is more concise and expandable:


Code: Select all

@echo off
  pushd "%1"
   for %%a in (exe bat) do ( 
       echo.
    for /f "delims=" %%b in ('dir /b /o:n "*.%%a"') do (
       echo.       %%~nb
    )
   )
  popd
  pause

maphew
Posts: 6
Joined: 05 Feb 2012 15:41

Re: how to use :Format function effectively

#12 Post by maphew » 14 Feb 2012 00:17

Hi Foxidrive, thanks for the suggestion. I'd tried earlier to go straight from `dir ...` to `%~ng% without a temp file but failed. Seeing your example I think I didn't have the delims right.

In any case, the 'dir /d' is get dir to do the heavy lifting of putting the names in columns, and 'findstr ...' is to strip the unwanted header and footer text.

The overall goal is to have a handy quick reference list of the commands in a certain bin directory without the distracting extensions and header/footer info as I'm forever forgetting just what is there or how they're spelled.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: how to use :Format function effectively

#13 Post by foxidrive » 14 Feb 2012 01:41

Hmmm. Something is screwy. I ran your code and it did not give me any columns, and I see why now.

It seems like if there are some long enough filenames then it doesn't use columns. See below.

Code: Select all

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

c:\bat>dir /d *.bat
 Volume in drive C is C
 Volume Serial Number is xxxx-xxxx

 Directory of c:\bat

#.BAT
0.BAT
7z.bat
===. albumfolder .===.bat
===. artist - albumfolder .===.bat
aa.bat
AAW.BAT
AGENT.BAT
AspectRatio.BAT
AU.BAT
BEEP.BAT
BM.BAT
C.BAT
CAVI.BAT
CAVI1.BAT
CAVI2.BAT

...

zip - unzip and rename File_ID.DIZ to filename_txt.BAT


Post Reply