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!