44

Suppose I have a value such as "Abc_123" that's stored in a variable in a batch (cmd) file. I want to end up with a variable that contains only "123". Is there any built-in way to do this?

I'm not terribly picky about the method, or performance, as long as it's built in to a typical Windows (Vista/2008) system.

I say Reinstate Monica
  • 25,487
  • 19
  • 95
  • 131
Ken
  • 585
  • 1
  • 5
  • 8

5 Answers5

57

Use the substring syntax:

C:\Users\John>set string=Abc_123

C:\Users\John>echo %string%
Abc_123

C:\Users\John>echo %string:~4,3%
123
John T
  • 163,373
  • 27
  • 341
  • 348
  • 6
    You can see the full syntax with `help set` as mentioned in [What is the best way to do a substring in a batch file?](http://stackoverflow.com/questions/636381/what-is-the-best-way-to-do-a-substring-in-a-batch-file) on StackOverflow. – User5910 Oct 25 '16 at 22:49
  • 5
    If I needed that 4 and 3 to be variable inputs, how would I do that? `%string:~%start%,%len%%` – ToMakPo Nov 18 '17 at 19:06
  • 2
    never mind. I found the answer. https://ss64.com/nt/syntax-substring.html – ToMakPo Nov 18 '17 at 19:27
  • 3
    To summarize the link from @MakPo: use `CALL`, like `CALL SET _substring=%%_donor:~%_startchar%,%_length%%%` – bugybunny Feb 04 '19 at 13:10
  • @ToMakPo The CALL solution is essential. i struggled til i found that, thx to you! Should be part of an answer. – johny why Nov 20 '21 at 17:44
14

If you just want everything after the underscore (and do not necessarily know the length of the string or where the underscore is, but can rely on there being only one underscore), try:

for /f "tokens=2 delims=_" %%a in ("%STRING%") do (
  set AFTER_UNDERSCORE=%%a
)

Basically, your string will be split into tokens using the underscore as a delimiter (delims=_). Only the second one (tokens=2) will be passed (as variable %%a) to the for loop. The loop will only run once since you are dealing with a single string in this case.

If you want to save the stuff both before and after the underscore, try:

for /f "tokens=1,2 delims=_" %%a in ("%STRING%") do (
  set BEFORE_UNDERSCORE=%%a
  set AFTER_UNDERSCORE=%%b
)

Note that %%a is the variable for the first token of the split; %%b is the variable for the second token of the split.

DocOc
  • 261
  • 2
  • 3
8
set var1=Abc_123
set var2=%var1:*_=%
echo %var2%
Zimba
  • 1,051
  • 11
  • 15
  • 5
    What does this do specifically? – Vomit IT - Chunky Mess Style Oct 29 '19 at 17:09
  • Oh, if you were asking how this code works: it removes everything before the number, preceded by an underscore. – Zimba Nov 23 '19 at 13:31
  • @Zimba is there a way to simply extend this to "last _"? Also where can I find this in any documentation? – TWiStErRob Jan 25 '20 at 00:40
  • Ok, found a docs, added to answer. Questions still stands: how do I make `*` greedy? I used a good ol' `IF NOT ... GOTO :replace`, but would be nice if there was a better way. – TWiStErRob Jan 25 '20 at 00:50
  • @TWiStErRob what did you mean 'how to make * greedy'? For question about "last _", did you mean if string was "last _123"? – Zimba Jan 29 '20 at 05:23
  • @Zimba `ser var1=abc_def_123`, still want 123 as result. I don't know how many `_` there are, there could be more than 2. – TWiStErRob Jan 29 '20 at 09:18
  • 1
    @TWiStErRob: I see. If you don't know how many `_` there are, then loop to the last one, then `set var` – Zimba Jan 29 '20 at 16:24
  • This works great, how about removing everything after underscore? Is there a simple solution similar with this one? – Joe Jobs Jun 24 '21 at 19:31
  • 2
    You mean to be left with Abc_, like a head function? – Zimba Jun 25 '21 at 17:24
  • I want something like a head function, i.e. given abc_def_123 I get abc_def. – phreed May 06 '22 at 22:19
  • I am also having trouble finding documentation for this pattern. Any links? – phreed May 06 '22 at 22:20
  • Found the reference -How-to: Edit/Replace text within a Variable (https://ss64.com/nt/syntax-replace.html) – clairestreb Jun 19 '22 at 16:05
  • lol I just noticed someone marked this answer for deletion. For documentation, search for [string substitution](https://ss64.com/nt/syntax-substring.html). For [head function](https://superuser.com/questions/859870/windows-equivalent-of-the-head-c-command) of a string, if search for string substitution or replacement doesn't answer your question, then post a new one, and I'll see what I can cook up – Zimba Jul 31 '22 at 04:10
2

This will extract last token from string with any tokens number and any type of delimiters. In this example ECHO will show "i". Although it requires a loop function, it's very fast.

@echo off
set "Var=a_b_c_d_e_f_g_h_i"
call :LoopLastToken "%Var%"
echo "%Var%"
pause
exit

:LoopLastToken
    set "Var=%~1"
    if not "%Var:*_=%"=="%~1" (
    call :LoopLastToken "%Var:*_=%")
exit /b
Alex D.
  • 21
  • 1
0

If you find that the batch language isn't powerful enough to do what you want - and it likely won't take you too long to get to that point - you can use the Windows PowerShell. This isn't installed by default on all versions of Windows, but you can download it free of charge.

If you don't like the PowerShell language, there's Perl. You'll have to install that on all systems though. There are others too.

Wayne Johnston
  • 3,538
  • 19
  • 15
  • 3
    The question is not asking about Powershell or Perl – Zimba Oct 29 '19 at 13:31
  • 1
    Powershell requires (much) more resources (RAM) than cmd so if all you need is something quick and simple, it makes more sense to use cmd. CMD uses native Win32 calls and Powershell uses the .Net framework. Powershell takes longer to load, and can consume a lot more RAM than CMD. *"I monitored a Powershell session executing Get-ChildItem. It grew to 2.5GB (all of it private memory) after a few minutes and was no way nearly finished. CMD “dir /o-d” with a small scrollback buffer finished in about 2 minutes, and never took more than 300MB of memory."* https://qr.ae/pGmwoe – johny why Nov 20 '21 at 17:52