Page 1 of 1

Trimming in a 'set' command via a variable

Posted: 25 Jan 2009 20:17
by Dyno
I'm trying to write a fileTrim function but having problems. I want to do a rename so the following happens with the commands:

set from="C:\test"
set trim="Microsoft "
call :fTrim

And the directory:
C:\test\Microsoft Excel.lnk
C:\test\Microsoft Word.lnk
C:\test\Office.lnk
C:\test\subdir\Microsoft Outlook.lnk

Results in:
C:\test\Excel.lnk
C:\test\Office.lnk
C:\test\Word.lnk
C:\test\subdir\Outlook.lnk

I have the following:

Code: Select all

:fTrim
for %%f in (%from%) do (
  for /F %%i in ('dir /b /s %%f\%trim%*.*') do (
    set newvar=%%~nxi
   
    rem The following line works:
    rem set newvar1=!newvar:Microsoft =!
   
    rem The following line, which uses the variable, doesn't work:
    set newvar1=!newvar:%trim%=!

    echo Orig: "%%i" New: "!newvar1!"
  )
)

I'd use a static string of "Microsoft " if I didn't need to change it, as to "Creative " for renaming things from Creative Labs (tm). I've tried substituting %trim% with !trim!, `!trim!`, but still can't seem to get 'set' to understand the variable.

Note that in order for 'for' to understand:
for /R %from% %%i in (%trim%*.*) do (
some contortions were needed. I used a shortcut for:
for /F "usebackq ...
which happens to work quite well and produces the recursive directory listing fine.

How do I get DOS under Windows 2000 to understand the %temp% so I can do: rename "Microsoft *.*" "*.*" and get it to understand it needs to strip out the "Microsoft " or "Creative " or other variable string?

Posted: 26 Jan 2009 23:04
by DosItHelp
Dyno,

There are two issues as far I can tell:

1.
The value of the "trim" variable contains quotes that's why it will not substitute the string. To use quotes with the "SET" command to specify the value but without adding the quotes to the value use:
set "trim=Microsoft "
not:
set trim="Microsoft "

2.
The "FOR /F" command uses a space as default delimiter. Since your file names to be trimmed contain spaces the %%i variable will only capture the part before the first space. To prevent the "FOR /F" command from using any delimiters use:
FOR /F "delims=" ...

So how about this:

Code: Select all

@Echo Off
Setlocal Enabledelayedexpansion
Set "from=C:\test"
Set "trim=Microsoft "
Call:fTrim
Goto:Eof

:fTrim
For %%f in ("%from%") do (
  For /F "delims=" %%i in ('dir /b /s "%%f\%trim%*.*"') do (
    Set "newvar=%%~nxi"
    Set "newvar1=!newvar:%trim%=!"
    Echo Orig: "%%i" New: "!newvar1!"
  )
)

Orig: "C:\test\Microsoft Excel.lnk" New: "Excel.lnk"
Orig: "C:\test\Microsoft Word.lnk" New: "Word.lnk"
Orig: "C:\test\subdir\Microsoft Outlook.lnk" New: "Outlook.lnk"

DosItHelp? :wink:

SOLVED by DosItHelp

Posted: 27 Jan 2009 17:22
by Dyno
I've never seen set "var=value". That was indeed the first part of solving the problem. The second was getting 'for' to work with the new variable, which you also correctly pointed out. Thank you!

The revised code (complete with problems and fixes) is below with better explainations of how things work.

Code: Select all

SETLOCAL ENABLEDELAYEDEXPANSION

rem The following variable should be defined before fTrim is called:
rem Trim files from directory:
set from="C:\test_dir_1\test_sub_2\test_sub2_2"
rem by trimming this from the front of the file:
rem set trim="test_file_"   # This won't work because of the quotes.
rem set trim=test_file_     # This will work for filenames without spaces.
set "trim=test_file_"       # This works for filenames with spaces. (User: DosItHelp at dostips.com)
set "trim=test file "
call :ftrim
goto :EOF

rem Filename Trim
:fTrim
  echo from: %from%
  echo trim: %trim%
 
  rem Process directory list.
  rem input: test_file_1.txt, proper output: 1.txt
  rem 2nd round input: test file 1.txt, proper output: 1.txt
  for %%f in (%from%) do (
   
    rem Process the next directory if no files match the trim parameter.
    dir /b /s "%%f\%trim%*.*" 2> nul | find /c /v "" 1> nul
    if errorlevel 1 (
      echo No matching files found.
    ) else (
     
      rem Recursively process each file that starts with 'trim'.
      rem for /F %%i in ('dir /b /s %%f\%trim%*.*') do (    # 'trim' with spaces blows up.
      rem for /F %%i in ('dir /b /s "%%f\%trim%*.*"') do (  # 'for' interprets spaces and seperates problematically.
      rem Set the delimiter from space to none.  (User: DosItHelp at dostips.com)
      for /F "delims=" %%i in ('dir /b /s "%%f\%trim%*.*"') do (

        rem The 'rename' command needs the full path, which 'i' holds, and
        rem the new filename.
       
        set oldName=%%~nxi
        echo Old file name: !oldName!

        rem The following line works, but doesn't use a variable:
        rem set newName=!oldName:test_file_=!
       
        rem The following line uses a variable, but doesn't work:
        rem set newName=!oldName:`echo.!trim!`=!    test_file_1.txt
        rem set newName=!oldName:%trim%=!           test_file_1.txt
        rem set newName=!oldName:!trim!=!           trim
        rem set newName=!oldName:^!trim^!=!         trim
        rem The following works properly when using set "trim=some value" instead of set trim="some value"
        set newName=!oldName:%trim%=!
       
        echo New file name: !newName!
       
        rem Uncomment the following line to do the rename. Remember the rename acts on all sub-folders also.
        rem rename "%%i" "!newName!"
      )
    ) 
  )
 
rem Function return.
goto :EOF


The code for creating the test directories follows. Change test_dir_%%d to "test dir %%d" to create file names with spaces. Otherwise, just rename a few files by hand to test things out.

Code: Select all

  rem ##sub################
  :mkTestDir
  rem Make test directories.
  rem Usage: mkTestDir [delete]
  rem #####################

  rem Remove old test directories.
  for %%d in (1 2) do (
    if exist C:\test_dir_%%d (
      rmdir /s /q C:\test_dir_%%d
      if exist C:\test_dir_%1 (
        echo FATAL: Could not remove: C:\test_dir_%%d
        set retStatus=Fail
        pause
        goto :EOF
      )
    )

    rem Don't create new directories if the 'delete' command was issued.
    if not "%1"=="delete" (
      rem Create two new test directories.
      rem echo Making C:\test_dir_%%d
      mkdir C:\test_dir_%%d
      if not exist C:\test_dir_%%d (
        echo FATAL: Could not create: C:\test_dir_%%d
        set retStatus=Fail
        pause
        goto :EOF
      )
    )
  )
  rem Don't populate new directories if the 'delete' command was issued.
  if "%1"=="delete" goto :EOF

  rem Populate first test directory.
  for %%f in (1 2) do echo Test file %%f. > C:\test_dir_1\test_file_%%f.txt
  for %%d in (1 2 3) do (
    mkdir C:\test_dir_1\test_sub_%%d
    for %%f in (1 2 3 4) do echo Test file %%d:%%f. > C:\test_dir_1\test_sub_%%d\test_file_%%f.txt
    for %%e in (1 2) do (
      mkdir C:\test_dir_1\test_sub_%%d\test_sub2_%%e
      for %%g in (1 2) do echo Test file %%d:%%e:%%g. > C:\test_dir_1\test_sub_%%d\test_sub2_%%e\test_file_%%g.txt
    )
  )

  set retStatus=
  goto :EOF