1. Reasons for not working batch file in question
The FOR loop approach in batch file in question does not work because of set "o=!%fileAdd:~%m%,%n%!" has a misplaced first % and %m% and %n% are already expanded by the Windows Command Processor cmd.exe on parsing the entire command block before executing the command FOR. That can be seen on running the batch file in a Command Prompt window without @echo off at top or with changing this line to @echo on. On each loop iteration is executed:
set "o=!https://upload.wikimedia.org/wikipedia/commons/9/9f/Vervet_monkey_(Chlorocebus_pygerythrus)_Maputo.jpgmn!"
%m% and %n% are already replaced by mn before the first FOR loop iteration.
See also: Variables are not behaving as expected
The command line with a removal of the first misplaced % would be:
set "o=!fileAdd:~%m%,%n%!"
That command line would be modified by cmd.exe before first loop iteration to:
set "o=!fileAdd:~,-1!"
%m% not defined at all above the FOR loop is replaced by an empty string and the environment variable reference %n% is replaced by -1 because of the environment variable n is defined with that string value above the FOR loop. This command line is executed repeatedly in the loop.
The correct syntax for using CALL would be:
call set "o=!fileAdd:~%%m%%,%%n%%!"
But there should not be used that command line because the use of CALL results not only in double parsing the command line before execution of command SET, but also searching in the current directory and next in all directories listed semicolon separated in string of environment variable PATH for a file matched by the wildcard pattern set.*. The command CALL is for calling a batch file from within a batch file and would be misused here to get set "o=!fileAdd:~%m%,%n%!" parsed once again by cmd.exe before the execution of command SET.
The batch file in question would not even work with correct command line using the command CALL.
2. Solution using file I/O functions of Windows
Here is a simple solution for this string extraction:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "fileAdd=https://upload.wikimedia.org/wikipedia/commons/9/9f/Vervet_monkey_(Chlorocebus_pygerythrus)_Maputo.jpg"
for %%I in ("%SystemDrive%\%fileAdd:/=\%") do for /F "tokens=1* delims=\:" %%G in ("%%~pI") do set "webPath=%%G://%%H"
set "webPath=%webPath:\=/%"
set webPath
endlocal
The url is prepended with the drive letter and the colon of the system drive which is usually C:. All / are additionally replaced by \ to form an absolute file name. The file name is not valid because of the character : after the protocol identifier like http, https, ftp.
The invalid absolute file name is for the example:
C:\https:\\upload.wikimedia.org\wikipedia\commons\9\9f\Vervet_monkey_(Chlorocebus_pygerythrus)_Maputo.jpg
The path without drive letter and colon and without the string after last
/ as got with %~pI is:
\https:\upload.wikimedia.org\wikipedia\commons\9\9f\
This string is parsed by a second FOR loop which splits up the path string into two parts.
- The first part is the protocol identifier, e.g.
http, https, ftp …
- The second part is everything after
:\ which is for the example:
upload.wikimedia.org\wikipedia\commons\9\9f\
These two strings are concatenated with inserting :// after the protocol
identifier.
The resulting string assigned to the environment variable webPath is:
https://upload.wikimedia.org\wikipedia\commons\9\9f\
A simple substring substitution replacing all \ by / converts the string back to an url without the (file name) string after last / and the result is:
https://upload.wikimedia.org/wikipedia/commons/9/9f/
Characters like %&!| in the url are no problem for this code.
This solution has two not obvious visible advantages:
cmd.exe is searching in file system for the directories:
C:\https:
C:\https:\upload.wikimedia.org
C:\https:\upload.wikimedia.org\wikipedia
C:\https:\upload.wikimedia.org\wikipedia\commons
C:\https:\upload.wikimedia.org\wikipedia\commons\9
C:\https:\upload.wikimedia.org\wikipedia\commons\9\9f
But that will be never successful because of second : in the directory paths making all the directory paths invalid. That is good in this special use case.
There is not used the command CALL with the command SET resulting in searching for set.* in current directory and all directories of the environment variable PATH which is never good in case of a file set.bat or set.cmd exists somewhere which is called in this case instead of running the internal command SET.
3. Solution using a GOTO loop
This solution uses a GOTO loop in the batch file which removes one character after the other from the url from the end until reaching last / of the url.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "fileAdd=https://upload.wikimedia.org/wikipedia/commons/9/9f/Vervet_monkey_(Chlorocebus_pygerythrus)_Maputo.jpg"
set "webPath=%fileAdd:~0,-1%"
:Loop
if not "%webPath:~-1%" == "/" set "webPath=%webPath:~0,-1%" & goto Loop
set webPath
endlocal
This loop solution looks simple but is horrible for the file system in comparison to the solution using the Windows file I/O functions because of dozens of opening the batch file, seeking for the label Loop, reading and parsing the next command line, closing the batch file, executing the command line and restarting the procedure again until the last / is found in the url. See: Why is a GOTO loop much slower than a FOR loop and depends additionally on power supply?