Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch file if string starts with

Tags:

batch-file

I'm trying to figure out if a string starts with a substring :

rem GetInput
if "%result%"=="cd *" goto Cd
:Cd
if "%result%"=="cd meow" Echo Going to directory 'meow'...

Unfortunately this not looping back to :Cd when it should. How can I detect if th string starts with cd ?

like image 621
Gaby Avatar asked Mar 19 '26 22:03

Gaby


2 Answers

If I understand this correctly, you're trying to determine whether that value for %result% begins with 'cd', and you're unsuccessfully using a * as a wildcard to determine this.

There are a few different ways to handle this. Here's one way: You can check to see if the first two characters are equal to 'cd':

if /i "%result:~0,2%"=="cd" goto Cd

set /? has more on this.

like image 172
Wes Larson Avatar answered Mar 23 '26 09:03

Wes Larson


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...

  1. Makes a new string that starts with needle
  2. 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.
  3. 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 page replaces 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!

like image 36
ruffin Avatar answered Mar 23 '26 09:03

ruffin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!