1

The following code is creating shortcuts to Paths listed in List.txt textfile (like C:/folder1/folder2/folder3/folder4), and saves all shortcuts to path specified in set SAVETO. How to extract each Folder3 (second last folder name of each row in List.txt, to use it then in %SAVETO% paths)?

<...>
SET "SAVETO=%userprofile%\desktop"
for /f "usebackq delims=" %%G IN ("List.txt") DO (
    call :createLink "%%~nG" "%%G"
)
goto :eof

:createLink
set SCRIPT="%TEMP%\%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%.vbs"
echo Set oWS = WScript.CreateObject("WScript.Shell") >> %SCRIPT%
echo sLinkFile = "%SAVETO%\%~1.lnk" >> %SCRIPT%
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %SCRIPT%
echo oLink.TargetPath = "%~2" >> %SCRIPT%
<...>

After receiving second last folder, the shortcut must be saved to:

D:/custompath/%Folder3-second last from row in List.txt%/

UPDATE: For example, this code is almost what I need, it extracts folder3 name, but I can't apply this to my code. And also it's not necessary for me to check equ "\"

setlocal EnableDelayedExpansion
set "var=C:\folder 1\folder 2\folder 3\folder 4\"
if "%var:~-1%" equ "\" set var=%var:~0,-1%
set var=%var:\=" "%
for %%a in ("%var%") do (
   set lastButOne=!lastFolder!
   set lastFolder=%%~a
)
echo Last but one: %lastButOne%

And when code returning second last folder name of current line from List.txt I want to use its name in save path C:/path/*Second Last Folder Name*/Shortcut. And I need to do this for each line separately. So if first line of List.txt is path C:/a/bbb/c then shortcut to this path must be saved to c:/custom_path/bbb/shortcut_name, for C:/ab/cd/efff/g it must be saved to c:/custom_path/efff/shortcut_name.

Stz
  • 61
  • 10
  • 2
    Just for your information, Windows uses a backslash as the directory separator. As for your task, I'd suggest that the easiest way to perform it would be to nest another `For` loop within the one shown, to generate the parent folder from `%%G`. – Compo Dec 24 '18 at 12:43
  • So, you will get the second last folder, as 1st loop will extract the last. The second, will extract (and hold) the second. – double-beep Dec 24 '18 at 12:45
  • Thanks for the idea, but I can't apply this method.. I'm getting only empty output with each code I've tried. I'm not very good in coding. I would be very very appreciated if you could help with this part. Tried to use ideas from few similar topics, but still no results.. Tried out [link](https://stackoverflow.com/questions/8385454/batch-files-list-all-files-in-a-directory-with-relative-paths) – Stz Dec 24 '18 at 13:37
  • Please [edit your question](https://stackoverflow.com/posts/53912264/edit) to show us the code you've tried, and explain/show us what happened when you ran it. If all you're wanting to do is to propagate the value of `%SAVETO%`, instead of using `%userprofile%\desktop` then you can even do it without a nested `For` loop. – Compo Dec 24 '18 at 14:32
  • If you add a 3rd argument `"%%~dpG"` to the call, you can use `%~n3` in the sub to have the 2nd last folder. –  Dec 24 '18 at 14:38
  • I've updated my question, I hope now it is more clear, thank you very much for your attention. – Stz Dec 25 '18 at 11:02

1 Answers1

1

UPDATE I've altered the code to get the parent directory name correctly.

This is an example of a nested FOR loop (referred to in the comments) that you could use to extract the parent of the directory that comes from each line of input.

@SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "delims=" %%G IN (List.txt) DO (
    SET "PARENT=%%~dpG"
    REM  Strip off the trailing backslash. ~p leaves the backslash at the end.
    SET "PARENT=!PARENT:~0,-1!"
    FOR /F "delims=" %%P IN ("!PARENT!") DO (
        CALL :createLink "%%~nxG" "%%~nxP" "%%~dpP"
    )
)
EXIT /B

:createLink will be invoked with the name of the "leaf" directory as the first parameter, the name (only—no path) of the parent dir of that directory, and the path to that directory's parent as the third. I realize this is not precisely what your code wants, but as I don't really understand what you want to accomplish (not that it's wrong—the way you're using the data just seems unusual to me), at least two of the three pieces of information here (though I don't know which two) seem like what you're asking for.

Though goto :eof generally works (unless you define :eof somewhere other than the end of the file), I prefer EXIT /B since it's straightforward and does exactly what you want.

For testing, I used this as List.txt

C:/folder1/folder2/folder3/folder4
C:/folder1/folder12/folder113/folder1114/folder/folder11115
C:\folderA\folderB\folderC\folderD

If I add some debugging to the above code:

@SETLOCAL ENABLEDELAYEDEXPANSION
@ECHO OFF
FOR /F "delims=" %%G IN (List.txt) DO (
    @ECHO G: %%~G
    SET "PARENT=%%~dpG"
    SET "PARENT=!PARENT:~0,-1!"
    FOR /F "delims=" %%P IN ("!PARENT!") DO (
        @ECHO P: %%~P
        CALL :createLink "%%~nxG" "%%~nxP" "%%~dpP"
    )
)
EXIT /B

:createLink
@ECHO :createLink
@ECHO   Arg 1: %~1
@ECHO   Arg 2: %~2
@ECHO   Arg 3: %~3
EXIT /B

Then the output I get when I run the script is:

G: C:/folder1/folder2/folder3/folder4
P: C:\folder1\folder2\folder3
:createLink
  Arg 1: folder4
  Arg 2: folder3
  Arg 3: C:\folder1\folder2\
G: C:/folder1/folder12/folder113/folder1114/folder/folder11115
P: C:\folder1\folder12\folder113\folder1114\folder
:createLink
  Arg 1: folder11115
  Arg 2: folder
  Arg 3: C:\folder1\folder12\folder113\folder1114\
G: C:\folderA\folderB\folderC\folderD
P: C:\folderA\folderB\folderC
:createLink
  Arg 1: folderD
  Arg 2: folderC
  Arg 3: C:\folderA\folderB\
mojo
  • 4,050
  • 17
  • 24
  • For now my code creating shortcuts to Paths listed in `List.txt` textfile. And I have only one way to save them - to same folder which is set in `set SAVETO` path. Each line in `List.txt` has different paths, where parent folder of each line (second last folder of each line) contains important name, which I want to use when I save each shortcut. I mean: each time, when code reads another line from `List.txt`, it must extract second last folder name and use it in save path separately for each shortcut: `set SAVETO=C:/path/Name of that second last folder/shortcut` – Stz Dec 25 '18 at 08:51
  • Still no results ... tried `for %%a in ("%%~dpG") do set LastFolder=%%~nxa` , [everything from there](https://stackoverflow.com/questions/280969/loop-over-folder-string-and-parse-out-last-folder-name) , still empty results.... – Stz Dec 26 '18 at 13:41
  • Do the folder names in `List.txt` have trailing backslashes/slashes? If so, they'll have to be stripped away. – mojo Dec 26 '18 at 13:57
  • Yes, they do. Here's two real examples of links listed in `List.txt` `U:\SHARE\NAME\SUPPLIER\CONTRACT Name Here\CODE` `U:\SHARE\NAME\SUPPLIER\CONTRACT Name 2 Here\OTHERCODE` – Stz Dec 26 '18 at 14:11
  • Mojo, thank you Very very much! Now it works... I'm only changed `"%%~dpP"` to `"%%G"` to receive correct full `TargetPath` for me here, as 3rd agrument `echo oLink.TargetPath = "%~3" >> %SCRIPT%`. Now this script fully solves my question. One question, is it possible to do something, if path in %~3 contains `,` or few `.`? I found that with input `S.R.L.` it outputs `S.R` – Stz Dec 27 '18 at 08:31
  • 1
    I updated the example code. `~n` just gets the basename. `~x` gets the extension. `~nx` gets both. I didn't think about having periods in the dir names (though that's completely legitimate). – mojo Dec 27 '18 at 15:19
  • This is awesome, works great, TY! But sorry, very last question, I found one more case with `&` symbol in folder name, when `%%~P` returns it right, as `.../folder & name/...` when it's going to `CALL :createLink `, `%~3` returns `.../folder` and says `name` is not a command. Is there a fast way to solve this? I tried to play with [this](https://stackoverflow.com/a/33351952/6701205), but that doesn't work... Btw, Wish you a Merry Christmas! :) – Stz Dec 28 '18 at 13:19
  • Make sure you quote `%~3` when you use it. E.g.: `@ECHO "%~3"` or `SET "TARGET=%~3"` – mojo Dec 28 '18 at 13:48
  • Strangely, it was the first thing I've checked out. each `SET` in my code quoted with `"`, but after your comment I've tried to quote also this part: `echo Creating ...\%~2\companies\%~1` which was made just for visuality, and, wow, now it reads `&` fine! Thank you! Question of the topic fully solved. – Stz Dec 29 '18 at 08:04