NDog
Is it possible to strip a folder, file and extension from a string only?
eg - \\uncpaththatdoesnot-exist\1\2\3\4\5\6\7\8\9\really long path\abcdefghijklmnopqrstuvwxyz\foo!OS!bar%PROMPT%baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder\myscript.sh
return these values
dir=\\uncpaththatdoesnot-exist\1\2\3\4\5\6\7\8\9\really long path\abcdefghijklmnopqrstuvwxyz\foo!OS!bar%PROMPT%baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder
file=myscript
extension=.sh
or with an incomplete path
eg - foo!OS!bar%PROMPT%baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder\myscript.sh
return these values
dir=foo!OS!bar%PROMPT%baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder
file=myscript
extension=.sh
the problem is that foo!OS!bar%PROMPT%baz could be considered a valid path, and or I might have a really long path.
I do not want to process the folder\file, only the string directly.
Last edited by NDog (24 Jun 2016 12:18)
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#2 24 Jun 2016 14:52
bluesxman
How is the string getting into your script? Handling special characters, like "%", could make this a tricky proposition.
cmd | *sh | ruby | chef
----------------------------
#3 24 Jun 2016 15:18
NDog
If I get it working I will post the script for you so you can see how the string is imported.
I want to split string based on the last delimiter.
eg
$var = adsflkj\sdfasd\fas\e23 \234 %325367\ \\\ sdflkjher
Everything to the left of the last '\' = $var[0] = adsflkj\sdfasd\fas\e23 \234 %325367\ \\
Everything to the right of the last '\' = $var[1] = sdflkjher
I'm interested to see if it's been done before... I have run into this issue many times with batch and would like to finally solve it.
If not possible theres always vbscript...
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#4 24 Jun 2016 18:50
RG
Try something like this: Edited so that it does not require SETLOCAL ENABLEDELAYEDEXPANSION
Code: Select all
@echo off
set "String=\\uncpaththatdoesnot-exist\1\2\3\4\5\6\7\8\9\really long path\abcdefghijklmnopqrstuvwxyz\foo!OS!bar%PROMPT%baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder\myscript.sh"
set "Folder="
set "File="
call :ParseString "%String%"
CALL set "ParentFolder=%%String:%File%=%%"
set "ParentFolder=%ParentFolder:~0,-1%"
echo(Dir=%ParentFolder%
call :DisplayFileExt "%File%"
pause
goto :eof
:ParseString & rem this is a recursive routine
rem 1=String
for /f "delims=\ tokens=1*" %%a in ('echo(%~1') do (
rem call set "Folder=%%File%%"
set File=%%a
if not "%%b"=="" call :ParseString "%%b"
)
goto :eof
:DisplayFileExt
REM 1=File.Ext
echo(File=%~n1
echo(Ext=%~x1
goto :eof
Windows Shell Scripting and InstallShield
----------------------------
#5 24 Jun 2016 19:47
NDog
You are right with the %% characters bluesxman! I don't think batch will play nicely with strings with those haha.
I'm still curious to know if this is possible in batch... Any takers?
In the meantime I have offloaded to vbsscript.
The following script is useful to copy files or folders from one location to another, preserving the file/folder structure on the destination. Simply paste the valid subpath at the top of the script that you want copied and the root source under _src= and the script will take care of the rest.
If you are trying to copy paths or strings with % or & characters it won't work. If you ^cancel^ them maybe? It handles the usual stuff well ! and spaces.
Code: Select all
copy-osx.cmd
@echo off&cls
goto :start
### folder pair ###
Archive\Keka
Desktop\Cool Retro Term
File Transfer\uTorrent
iLife\iMovie 9 updates
Video\Quicktime Pro
### file pairs ###
KeepUpdates.rtf
## archive
Archive\DropDMG\DropDMG-3.3.dmg
## Office 2011
OSX\Office\Microsoft Office 2011\SW_DVD5_Office_Mac_Standard_2011w_SP3_English_ISO_MLF_X18-77844.ISO
OSX\Office\Microsoft Office 2011\Office2011-1465Update_EN-US.dmg
## development
Development\Python\pycharm-professional-2016.1.dmg
Development\Python\python-3.5.1-macosx10.6.pkg
Development\Swift\Xcode 7.3.1.dmg
Development\Swift\install-xcode.sh
## desktop
Desktop\Flux\Flux.zip
NTFS Support\Paragon NTFS\OSX 10.11\Batman Paragon NTFS 14.dmg
:start
@echo off&cls
setlocal
color 9f
title %~n0 - ndog
:: copy-osx.cmd
:: last updated @ 24/06/2016 - ndog
::
:: copies files or folders from the source '_src' to the destination '_dst'
:: desired file and folder paths are specified at the top of the script
::
:: advantage of this script is you do not have to define a destination location
:: as the script automatically creates directory structure on the destination based on the source
:: it is fast and efficient and will not copy files needlessly
set _src=\\saturn\~USB\install\OSX
set _dst=D:\install\osx
set _robocopy=%~dp0robocopy.exe
set _fsync=%~dp0fsync.exe
:: read pairs into memory
for /f "tokens=* usebackq" %%g in (%0) DO (
if exist "%_src%\%%g" call :sub_addarray "%%g"
if "%%g" equ ":start" goto :exitloop
)
:exitloop
:: menu
echo Source: %_src%
echo Destination: %_dst%
echo.
echo Located pairs...
for /f "usebackq tokens=1-2* delims==" %%g in (`set _pair_ 2^>nul`) do (echo ^> %%h)
echo.
pause
color 4f
:: offload to vbscript to process file/folder paths
set _tmpvbs=%temp%\splitpath.vbs
if not exist "%_tmpvbs%" goto :sub_stringsplitvbs
:: process pairs in memory
for /f "usebackq tokens=1-2* delims==" %%g in (`set _pair_`) do (
rem echo g %%g
rem echo h %%h
rem cscript //nologo "%_tmpvbs%" "%%h"
for /f "tokens=*" %%i in ('cscript //nologo "%_tmpvbs%" "%%h"') do (
rem echo i %%i
call :sub_processpair %%i
)
)
:end
:: finished
color 2f
pause
endlocal
:sub_addarray
set _string=%1
set _string=%_string:~1%
set _string=%_string:~0,-1%
set /a _filecount+=1
if %_filecount% lss 10 set _pair_0%_filecount%=%_string%
if %_filecount% geq 10 set _pair_%_filecount%=%_string%
set _string=
goto :eof
:sub_processpair
:: %1 = folder, %2 = file
rem echo %1
rem echo %2
set _dir=%1
set _dir=%_dir:~1%
set _dir=%_dir:~0,-1%
md "%_dst%\%_dir%" 2>nul
if [%2] == [] (
rem folder operation
"%_fsync%" "%_src%\%_dir%" "%_dst%\%_dir%" /f /c
goto :eof
)
rem file operation
set _file=%2
set _file=%_file:~1%
set _file=%_file:~0,-1%
rem echo %_dir%
rem echo %_file%
if defined _dir (
"%_robocopy%" "%_src%\%_dir%" "%_dst%\%_dir%" "%_file%" /NJH /NJS
) else (
"%_robocopy%" "%_src%" "%_dst%" "%_file%" /NJH /NJS
)
goto :eof
:sub_stringsplitvbs
echo ' full path passed as an argument encapsulated with "" speech marks>"%_tmpvbs%"
echo filepath = wscript.arguments(0)>>"%_tmpvbs%"
echo.>>"%_tmpvbs%"
echo ' split path into array based on '\' character>>"%_tmpvbs%"
echo patharray = split(filepath, "\")>>"%_tmpvbs%"
echo ' look for presence of a file if '.' character in string>>"%_tmpvbs%"
echo dotfile = instrrev(filepath, ".")>>"%_tmpvbs%"
echo.>>"%_tmpvbs%"
echo ' check for path in root>>"%_tmpvbs%"
echo if ubound(patharray) = 0 then>>"%_tmpvbs%"
echo if dotfile ^> 0 then>>"%_tmpvbs%"
echo file = filepath>>"%_tmpvbs%"
echo wscript.echo """" + """ """ + file + """">>"%_tmpvbs%"
echo wscript.quit>>"%_tmpvbs%"
echo else>>"%_tmpvbs%"
echo dir = filepath>>"%_tmpvbs%"
echo wscript.echo """" + dir + """">>"%_tmpvbs%"
echo wscript.quit>>"%_tmpvbs%"
echo end if>>"%_tmpvbs%"
echo end if>>"%_tmpvbs%"
echo.>>"%_tmpvbs%"
echo ' loop through elements to build a complete parent path>>"%_tmpvbs%"
echo for i = lbound(patharray) to ubound(patharray) - 1 >>"%_tmpvbs%"
echo parent_dir = parent_dir + patharray(i) + "\">>"%_tmpvbs%"
echo next>>"%_tmpvbs%"
echo.>>"%_tmpvbs%"
echo ' look for file>>"%_tmpvbs%"
echo ' return string encapsulated "folder" "file">>"%_tmpvbs%"
echo if dotfile ^> 0 then>>"%_tmpvbs%"
echo file = patharray(ubound(patharray))>>"%_tmpvbs%"
echo dir = left(parent_dir, len(parent_dir) - 1)>>"%_tmpvbs%"
echo wscript.echo """" + dir + """ """ + file + """">>"%_tmpvbs%"
echo wscript.quit>>"%_tmpvbs%"
echo else>>"%_tmpvbs%"
echo dir = filepath>>"%_tmpvbs%"
echo wscript.echo """" + dir + """">>"%_tmpvbs%"
echo wscript.quit>>"%_tmpvbs%"
echo end if>>"%_tmpvbs%"
goto :eof
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#6 25 Jun 2016 07:35
NDog
Thanks RG
I see your script does what I asked. I will try to get it integrated into my script as it seems to work well. Will post back here when I get it working!
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#7 26 Jun 2016 10:26
NDog
@RG
I like how your code is clever and strips the %File% string off the end original %String%, resulting in dividing the string in half effectively. I learnt something new today!
However is it possible to do this without setlocal enabledelayedexpansion?
Code: Select all
setlocal enabledelayedexpansion
set "ParentFolder=!String:%File%=!"
set "ParentFolder=%ParentFolder:~0,-1%"
echo(Dir=%ParentFolder%
Code: Select all
set str=4\5\6\(Video)
set str=%str:(Video)=%
echo %str% ---- str
Code: Select all
set str=1\2\3\4124 2354.txt
set file=4124 2354.txt
set str=%str:%file%=%
echo -- %str% --
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#8 27 Jun 2016 04:03
RG
Thanks @NDog, I edited my code above. It no longer requires setlocal enabledelayedexpansion
Windows Shell Scripting and InstallShield
----------------------------
#9 27 Jun 2016 04:27
Shadow Thief
Interestingly, it seems that batch will treat the string like a path even when the path does not exist.
Code: Select all
@echo off
set "fake_path=C:\this\path\is\definitely\fake.jpg"
:: %fake_path% is being treated like a string here
for /f %%A in ("%fake_path%") do (
echo Path: %%~dpA
echo File: %%~nA
echo Extension: %%~xA
)
pause
Path: C:\this\path\is\definitely\
File: fake
Extension: .jpg
Last edited by Shadow Thief (27 Jun 2016 04:32)
----------------------------
#10 27 Jun 2016 09:24
bluesxman
RG: your answer seems to fall foul of what I was talking about with "%" handling.
Here's the output I get:
Code: Select all
Dir=\\uncpaththatdoesnot-exist\1\2\3\4\5\6\7\8\9\really long path\abcdefghijklmnopqrstuvwxyz\foo!OS!bar:: $p$_:: $d $t $g baz\ 34234 \Technical Experts Exchange ss64 rocks\RD 123\VPN 456\parent folder
File=myscript
Ext=.sh
There are a couple of possibilities I can think of for making this word in pure cmd.
- Pre-processing of the input value to replace "%" with "%%" (arguably not pure cmd as this would, by definition, need an external tool)
- Input value arrives via a text input file or as the result of a command (such that this can be fed into for /f)
Last edited by bluesxman (29 Jun 2016 08:32)
cmd | *sh | ruby | chef
----------------------------
#11 27 Jun 2016 15:44
Aacini
Yes. When you try to get certain values of a file name that don't exist, there are "default values" if the file name don't include they; for example, the current drive and path. Only the file date, size and attributes are returned as empty strings if the file not exist.Shadow Thief wrote:
Interestingly, it seems that batch will treat the string like a path even when the path does not exist.
----------------------------
#12 28 Jun 2016 08:17
foxidrive
My own personal view is that people get what they deserve if they try to handle percent signs as regular characters in batch code. big_smilebluesxman wrote:
RG: your answer seems to fall foul of what I was talking about with "%" handling.
Having an unbalanced number of percent signs plus an environment variable in there will often lead to baldness! smile
----------------------------
#13 29 Jun 2016 11:26
NDog
Thanks RG, bluesxman and foxidrive - I'm always learning from you!
Also bluesxman I stole your percentage idea from the wim forum post
I hope you will give this script a test run and let me know if you think it could be improved!
Code: Select all
copy-pairs-wintest.cmd
@echo off&cls
goto :start
### folder pairs ###
repair
system32\DriverStore\FileRepository
system32\drivers\etc
### file pairs ###
hh.exe
system32\accwiz.exe
Media\start.wav
:start
@echo off&cls
setlocal
color 9f
set title=copy-pairs v1.2
title %title%
:: last updated @ 29/06/2016 - ndog
:: credits - RG (stringsplit method), bluesxman (percentage bar)
::
:: requires fsync.exe and robocopy.exe in the same folder as this script
:: fsync - http://www.vicobiscotti.it/en/fsync.htm
:: robocopy - https://www.microsoft.com/en-nz/download/details.aspx?id=17657
::
:: copies files or folders from the source '_src' to the destination '_dst'
:: desired file and folder paths are specified at the top of the script
:: advantage of this script is you do not have to define destinations for each pair
:: as the script automatically creates directory structure on the destination based on the source
:: it is fast and efficient and will not copy files needlessly
:: define source and destination location
set _src=C:\WINDOWS
set _dst=C:\test\syncpairs
:: dependancies
set _robocopy=%~dp0robocopy.exe
set _fsync=%~dp0fsync.exe
:: read pairs into memory
for /f "tokens=* usebackq" %%g in (%0) DO (
if exist "%_src%\%%g" call :sub_addarray "%%g"
if "%%g" equ ":start" goto :exitloop
)
:exitloop
:: menu
echo Source: %_src%
echo Destination: %_dst%
echo.
echo Located pairs...
for /f "usebackq tokens=1-2* delims==" %%g in (`set _pair_ 2^>nul`) do (echo ^> %%h)
echo.
echo MAKE SURE YOU BACKUP ANY MODIFIED FILES ON DESTINATION BEFORE CONTINUING!!!
pause
color 4f
:: process pairs in memory
for /f "usebackq tokens=1-2* delims==" %%g in (`set _pair_`) do (
rem echo g %%g
rem echo h %%h
for /f "delims=\ tokens=1*" %%i in ('echo %%h') do (
rem echo i %%i
rem echo j %%j
set /a _processcount += 1
if [%%j] == [] (
REM root path - no '\' found
call :parse_fileorfolder "%%i"
) else (
REM subpath - '\' found
call :sub_processfullpath "%%h"
)
call :global_processpair
set _folder=&set _file=&set _fileextension=
)
)
:end
:: finished
color 2f
ping localhost -n 5 >nul
endlocal
:sub_addarray
set _string=%~1
set /a _paircount+=1
if %_paircount% lss 10 set _pair_0%_paircount%=%_string%
if %_paircount% geq 10 set _pair_%_paircount%=%_string%
set _string=
goto :eof
:parse_fileorfolder
:: determine if a string is a file or folder based on the presence of a '.' + extenstion
if [%~x1] == [] (
set _folder=%~1
goto :eof)
set _file=%~n1
set _fileextension=%~x1
goto :eof
:sub_processfullpath
:: check for path in subfolder ('\' characters found)
set _string=%~1
call :parse_filepath "%_string%"
call :parse_fileorfolder "%_rightstring%"
call :parse_parentfolder "%_string%" "%_rightstring%"
set _string=
goto :eof
:parse_filepath
:: recurse through a "folder\file.ext" string and retrieve the right most variable after final '\' character
for /f "delims=\ tokens=1*" %%g in ('echo %~1') do (
set _rightstring=%%g
if not [%%h] == [] call :parse_filepath "%%h"
)
goto :eof
:parse_parentfolder
:: find value to left of final '\' character of the path string
set _path=%~1
set _right=%~2
call set _parentfolder=%%_path:%_right%=%%
set "_parentfolder=%_parentfolder:~0,-1%"
goto :eof
:global_processpair
:: read global variables
:: percent bar
set /a _perc=( %_processcount% * 100 ) / %_paircount%
if defined _folder title %title% - [%_processcount%/%_paircount%] %_perc%%% - %_folder%
if defined _file title %title% - [%_processcount%/%_paircount%] %_perc%%% - %_file%%_fileextension%
:: create: folder operation - root
if defined _folder if not defined _parentfolder md "%_dst%\%_folder%" 2>nul
:: create: folder operation - subfolder
if defined _folder if defined _parentfolder md "%_dst%\%_parentfolder%\%_folder%" 2>nul
:: folder operation - root
if defined _folder if not defined _parentfolder "%_fsync%" "%_src%\%_folder%" "%_dst%\%_folder%" /f /c
:: folder operation - subfolder
if defined _folder if defined _parentfolder "%_fsync%" "%_src%\%_parentfolder%\%_folder%" "%_dst%\%_parentfolder%\%_folder%" /f /c
:: file operation - root
if defined _file if not defined _parentfolder "%_robocopy%" "%_src%" "%_dst%" "%_file%%_fileextension%" /NJH /NJS
:: file operation - subfolder
if defined _file if defined _parentfolder "%_robocopy%" "%_src%\%_parentfolder%" "%_dst%\%_parentfolder%" "%_file%%_fileextension%" /NJH /NJS
goto :eof
cmd, vbs, ps, bash
autoit, python, swift
----------------------------
#14 03 Jul 2016 23:27
Sponge Belly
Hi NDog,
You can extract from the last backslash to the end of string like so:
set "filename=%longpath:\=" & set "filename=%"
Bizarre, but it works! smile
Read this DosTips Thread:
http://www.dostips.com/forum/viewtopic.php?f=3&t=6429
for the full story.
HTH!
- SB
----------------------------
#15 04 Jul 2016 08:42
bluesxman
That hurts my brain.
cmd | *sh | ruby | chef
----------------------------
#16 08 Jul 2016 09:14
foxidrive
Agree. My brain exploded.bluesxman wrote:
That hurts my brain.