The title is broader than the use case, which makes a generic startsWith a bit of overkill for the specific question -- as Wes says, for this specific question, you could just check the first two characters and check for cd.
But that in mind, let's answer the more generic question from the title.
A Generic startsWith
DOSTips.com's solution for startsWith looks pretty good.
:StartsWith text string -- Tests if a text starts with a given string
:: -- [IN] text - text to be searched
:: -- [IN] string - string to be tested for
:$created 20080320 :$changed 20080320 :$categories StringOperation,Condition
:$source https://www.dostips.com
SETLOCAL
set "txt=%~1"
set "str=%~2"
if defined str call set "s=%str%%%txt:*%str%=%%"
if /i "%txt%" NEQ "%s%" set=2>NUL
EXIT /b
An easier to read refactor? (TL;DR -- this is the answer)
That seems to work, but it doesn't really return a value and its variable names are very 1990s.
I hacked to this:
:startsWith
set "haystack1=%~1"
set "needle2=%~2"
if defined needle2 call set "s=%needle2%%%haystack1:*%needle2%=%%"
if /i "%haystack1%" NEQ "%s%" (
exit /b 0
)
EXIT /b 1
That will return a 1 in %errorlevel% for yes, does-start-with, and 0 for no, does-NOT-start-with. You could argue that does-start-with should return a 0 for "no error". If you feel strongly, you're obviously welcome to swap those in your implementation. I'm going with the "zero is traditionally falsy so it represents a false return value". YMMV, .
Test the implementation
And here's a full example to test...
@ECHO OFF
call :startsWith slappy slap
echo %errorlevel%
echo.
call :startsWith slap slappy
echo %errorlevel%
echo.
call :startsWith slappy spam
echo %errorlevel%
echo.
call :startsWith slappy lap
echo %errorlevel%
echo.
call :startsWith spam
echo %errorlevel%
echo.
exit /b 0
:startsWith
set "haystack1=%~1"
set "needle2=%~2"
set "s="
REM I think this is okay b/c if %2 was defined, %1 kinda has to be too.
if defined needle2 call set "s=%needle2%%%haystack1:*%needle2%=%%"
echo needle: %needle2%
echo haystack: %haystack1%
echo s: %s%
if /i "%haystack1%" NEQ "%s%" (
exit /b 0
)
EXIT /b 1
Output
needle: slap
haystack: slappy
s: slappy
1
needle: slappy
haystack: slap
s: slappyslap
0
needle: spam
haystack: slappy
s: spamslappy
0
needle: lap
haystack: slappy
s: lappy
0
needle:
haystack: spam
s:
0
It's a neat trick. It basically...
- Makes a new string that starts with
needle
- If
needle occurs anywhere in haystack, add the portion of haystick that occurs after needle's appearance to the new string. Otherwise add all of haystack to your new string.
- If this new string matches
haystack, you win! Else you lose.
So if needle is slap and haystack is slappy, %s% will be slap plus [everything after slap in slappy which is...] py. That gives us slappy, which matches what was in haystack, and we win.
If needle is spam and haystack is slappy, %s% will start with spam and then, since spam isn't in slappy, we add all of haystack. That leaves us with spamslappy and we lose. (spamslappy? Now that's comedy.)
And a neat fail is when you look for something that is in but not at the start of the haystack, like in our lap example. That is, if the needle is lap and haystack is slappy, %s% will start with lap and then, everything from the end of lap in slappy also gives py, we have lap plus py or lappy, which isn't slappy, and we lose again, but in a new, cool way.
Your batch syntax questions answered (maybe)
What's the tilde in set "needle2=%~2"?
Argument quote removal. A tilde sign before an command-line argument (such as "%~1") indicates to remove the surrounding quotes from the parameter. Such if the value for %1 is "Hi" then %~1 will expand to only Hi.
call set "s=%str%%%txt:*%str%=%%" is a little more convoluted.
First understand that the colon (:) means we're using "the string substitution feature":
This code taken from the same pagereplaces needs with has in %str:
set str=%str:needs=has%
echo %str%
Then we need to know that...
"StrToFind" [after the :] can begin with an asterisk, in which case it will replace all characters to the left of "StrToFind".
...
::Delete the character string 'ab' and everything before it
SET _test=12345abcabc
SET _result=%_test:*ab=%
ECHO %_result% =cabc
Then see this answer:
The call there causes another layer of variable expansion, making it necessary to [escape] the original % signs but it all works out in the end.
Now call set "s=%str%%%txt:*%str%=%%" should make sense.
Another answer on that question shows that the method of startsWith from DOSTips is a little less finnicky than the other answer here as...
You can use !, but you must have the ENABLEDELAYEDEXPANSION switch set.
We're avoiding that.
And, finally...
If you are aghast at the insanity of all these arcane rules, you should be learning PowerShell, it's awesome!
Ha! Okay, but we can still get it done without leaving batch. Enjoy!