79

Suppose I have a string "AAA BBB CCC DDD EEE FFF".

How can I split the string and retrieve the nth substring, in a batch file?

The equivalent in C# would be

"AAA BBB CCC DDD EEE FFF".Split()[n]
Veverke
  • 9,208
  • 4
  • 51
  • 95
Cheeso
  • 189,189
  • 101
  • 473
  • 713

16 Answers16

60

Three possible solutions to iterate through the words of the string:

Version 1:

@echo off & setlocal
set s=AAA BBB CCC DDD EEE FFF
for %%a in (%s%) do echo %%a

Version 2:

@echo off & setlocal
set s=AAA BBB CCC DDD EEE FFF
set t=%s%
:loop
for /f "tokens=1*" %%a in ("%t%") do (
   echo %%a
   set t=%%b
   )
if defined t goto :loop

Version 3:

@echo off & setlocal
set s=AAA BBB CCC DDD EEE FFF
call :sub1 %s%
exit /b
:sub1
if "%1"=="" exit /b
echo %1
shift
goto :sub1

Version 1 does not work when the string contains wildcard characters like '*' or '?'.

Versions 1 and 3 treat characters like '=', ';' or ',' as word separators. These characters have the same effect as the space character.

Christian d'Heureuse
  • 5,090
  • 1
  • 32
  • 28
  • Version 1 also works for comma-separated lists, e.g. ABC,DEF,GHI,JKL – FrinkTheBrave Dec 22 '14 at 15:36
  • Great! Used `set /p s= – sjoy Mar 06 '15 at 19:22
  • 1
    Version 2 is the best for (most) arbitrary delimiter characters. – mojo Aug 20 '15 at 15:36
  • 2
    In Version 2: what exactly is `set t=%%b`doing? Where does it come from? Sorry I don't get it. Would please explain? Thank you. – snahl Nov 11 '15 at 08:42
  • 5
    @snahl In version 2,`%%b` contains the remaining words. `set t=%%b` removes the first word from the variable `t`. The "for" loop is only executed once per pass, because the `/f` parameter is specified and `("%t%")` is only a single line of text. The "goto :loop" is the actual loop that is executed once per word. – Christian d'Heureuse Nov 11 '15 at 21:05
36

see HELP FOR and see the examples

or quick try this

 for /F %%a in ("AAA BBB CCC DDD EEE FFF") do echo %%a
Magoo
  • 77,302
  • 8
  • 62
  • 84
PA.
  • 28,486
  • 9
  • 71
  • 95
  • Thanks, this definitely works. I was hoping to be able to parameterize it, so I could get the nth string, not ... the 3rd string (%%c). or the 4th string (%%d). – Cheeso Nov 10 '09 at 11:31
  • Note that this also breaks at '=' (and possibly others as well) – SvenS Jun 26 '14 at 09:21
  • 4
    either I'm doing something wrong or this doesn't work anymore. For me it just outputs "%c" – xeruf Jun 26 '17 at 10:43
  • 5
    For me it didn't work until I added "tokens=1,2" after /F, or only the first variable was set (%%a). – Gabriel Hautclocq Jul 06 '17 at 11:45
  • Additionally this is possible too `FOR /F "delims=- tokens=1-3" %%a IN ("AAA-BBB-CCC-DDD-EEE-FFF") DO ECHO %%a&ECHO %%b&ECHO %%c` – Arvo Bowen Aug 10 '18 at 16:25
  • 9
    Looks like doesn't work on Windows 10. Maybe that should be added to the reply. – Florian Straub Jul 12 '19 at 16:39
  • for more information and further research : [**for** loop on __ss64__](https://ss64.com/nt/for.html) – Danilo May 02 '21 at 12:07
  • As originally posted, it has never worked. As edited, it worked, As rolled-back, it returned to non-working. Now re-rolled-back and working, but it does not answer the "how do I retrieve the nth substring" part, so why it's an accepted answer is a complete mystery. A better answer would be `for /F "tokens=%n%" %%a in ("AAA BBB CCC DDD EEE FFF") do echo %%a` where the variable `n` contains the required substring-number. – Magoo Mar 21 '22 at 02:40
  • it worked. As originally posted it highlighted the fact that you can choose the substring desired out of a bunch of splitted substrings. – PA. Mar 21 '22 at 12:25
34

This is the only code that worked for me:

for /f "tokens=4" %%G IN ("aaa bbb ccc ddd eee fff") DO echo %%G 

output:

ddd
Scott E
  • 449
  • 4
  • 3
16

If someone need to split a string with any delimiter and store values in separate variables, here is the script I built,

FOR /F "tokens=1,2 delims=x" %i in ("1920x1080") do (
  set w=%i
  set h=%j
)
echo %w%
echo %h%

Explanation: 'tokens' defines what elements you need to pass to the body of FOR, with token delimited by character 'x'. So after delimiting, the first and second token are passed to the body. In the body %i refers to first token and %j refers to second token. We can take %k to refer to 3rd token and so on..

Please also type HELP FOR in cmd to get a detailed explanation.

Praveen Tiwari
  • 1,200
  • 1
  • 12
  • 25
14

The following code will split a string with an arbitrary number of substrings:

@echo off
setlocal ENABLEDELAYEDEXPANSION

REM Set a string with an arbitrary number of substrings separated by semi colons
set teststring=The;rain;in;spain

REM Do something with each substring
:stringLOOP
    REM Stop when the string is empty
    if "!teststring!" EQU "" goto END

    for /f "delims=;" %%a in ("!teststring!") do set substring=%%a

        REM Do something with the substring - 
        REM we just echo it for the purposes of demo
        echo !substring!

REM Now strip off the leading substring
:striploop
    set stripchar=!teststring:~0,1!
    set teststring=!teststring:~1!

    if "!teststring!" EQU "" goto stringloop

    if "!stripchar!" NEQ ";" goto striploop

    goto stringloop
)

:END
endlocal
P4ul
  • 770
  • 5
  • 15
Dave
  • 3,429
  • 2
  • 26
  • 29
  • If you remove the `ENABLEDELAYEDEXPANSION` and replace all `!` with `%`, it seems to work as well. Or do you need that setting for something in particular? – Andrew May 23 '20 at 00:04
9

easy

batch file:

FOR %%A IN (1 2 3) DO ECHO %%A

command line:

FOR %A IN (1 2 3) DO ECHO %A

output:

1
2
3
capdragon
  • 14,565
  • 24
  • 107
  • 153
8

I ended up with the following:

set input=AAA BBB CCC DDD EEE FFF
set nth=4
for /F "tokens=%nth% delims= " %%a in ("%input%") do set nthstring=%%a
echo %nthstring%

With this you can parameterize the input and index. Make sure to put this code in a bat file.

Bruno
  • 1,213
  • 13
  • 14
  • This was just what I needed for extracting major and minor versions from a version string in a post build. Thanks! – tobriand May 07 '15 at 14:46
4

The following code will split a string with N number of substrings with # separated values. You can use any delimiter

@echo off
if "%1" == "" goto error1

set _myvar="%1"

:FORLOOP
For /F "tokens=1* delims=#" %%A IN (%_myvar%) DO (
    echo %%A
    set _myvar="%%B"
    if NOT "%_myvar%"=="" goto FORLOOP
)

goto endofprogram
:error1
echo You must provide Argument with # separated

goto endofprogram
:endofprogram
JBL
  • 12,588
  • 4
  • 53
  • 84
3

or Powershell for a 0 indexed array.

PS C:\> "AAA BBB CCC DDD EEE FFF".Split()
AAA
BBB
CCC
DDD
EEE
FFF

PS C:\> ("AAA BBB CCC DDD EEE FFF".Split())[0]
AAA
Timtech
  • 1,224
  • 2
  • 19
  • 30
ecciethetechie
  • 157
  • 1
  • 2
2
set a=AAA BBB CCC DDD EEE FFF
set a=%a:~6,1%

This code finds the 5th character in the string. If I wanted to find the 9th string, I would replace the 6 with 10 (add one).

RustyTheBoyRobot
  • 5,891
  • 4
  • 36
  • 55
Jon
  • 37
  • 1
2
@echo off

:: read a file line by line
for /F  %%i in ('type data.csv') do (
    echo %%i
    :: and we extract four tokens, ; is the delimiter.
    for /f "tokens=1,2,3,4 delims=;" %%a in ("%%i") do (
        set first=%%a&set second=%%b&set third=%%c&set fourth=%%d
        echo %first% and %second% and %third% and %fourth% 
    )
)
Pello X
  • 481
  • 4
  • 2
2

Here is a solution based on a "function" which processes each character until it finds the delimiter character.

It is relatively slow, but it is at least not a brain teaser (except for the function part).

:: Example #1:
set data=aa bb cc
echo Splitting off from "%data%":
call :split_once "%data%" " " "left" "right"
echo Split off: %left%
echo Remaining: %right%
echo.

:: Example #2:
echo List of paths in PATH env var:
set paths=%PATH%
:loop
    call :split_once "%paths%" ";" "left" "paths"
    if "%left%" equ "" goto loop_end
    echo %left%
goto loop
:loop_end



:: HERE BE FUNCTIONS
goto :eof

:: USAGE:
::   call :split_once "string to split once" "delimiter_char" "left_var" "right_var"
:split_once
    setlocal
    set right=%~1
    set delimiter_char=%~2
    set left=

    if "%right%" equ "" goto split_once_done

    :split_once_loop
        if "%right:~0,1%" equ "%delimiter_char%" set right=%right:~1%&& goto split_once_done
        if "%right:~0,1%" neq "%delimiter_char%" set left=%left%%right:~0,1%
        if "%right:~0,1%" neq "%delimiter_char%" set right=%right:~1%
        if "%right%" equ "" goto split_once_done
    goto split_once_loop

    :split_once_done
    endlocal & set %~3=%left%& set %~4=%right%
goto:eof
blackwell
  • 21
  • 1
0

you can use vbscript instead of batch(cmd.exe)

Set objFS = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
str1 = objArgs(0)
s=Split(str1," ")
For i=LBound(s) To UBound(s)
    WScript.Echo s(i)
    WScript.Echo s(9) ' get the 10th element
Next

usage:

c:\test> cscript /nologo test.vbs "AAA BBB CCC"
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
0

UPDATE: Well, initially I posted the solution to a more difficult problem, to get a complete split of any string with any delimiter (just changing delims). I read more the accepted solutions than what the OP wanted, sorry. I think this time I comply with the original requirements:

 @echo off
 IF [%1] EQU [] echo get n ["user_string"] & goto :eof
 set token=%1
 set /a "token+=1"
 set string=
 IF [%2] NEQ [] set string=%2
 IF [%2] EQU [] set string="AAA BBB CCC DDD EEE FFF"
 FOR /F "tokens=%TOKEN%" %%G IN (%string%) DO echo %%~G

An other version with a better user interface:

 @echo off
 IF [%1] EQU [] echo USAGE: get ["user_string"] n & goto :eof
 IF [%2] NEQ [] set string=%1 & set token=%2 & goto update_token
 set string="AAA BBB CCC DDD EEE FFF"
 set token=%1
 :update_token
 set /a "token+=1"
 FOR /F "tokens=%TOKEN%" %%G IN (%string%) DO echo %%~G

Output examples:

E:\utils\bat>get
USAGE: get ["user_string"] n
E:\utils\bat>get 5
FFF
E:\utils\bat>get 6
E:\utils\bat>get "Hello World" 1
World

This is a batch file to split the directories of the path:

@echo off
set string="%PATH%"
:loop
FOR /F "tokens=1* delims=;" %%G IN (%string%) DO (
    for /f "tokens=*" %%g in ("%%G") do echo %%g
    set string="%%H"
    )
if %string% NEQ "" goto :loop

2nd version:

@echo off
set string="%PATH%"
:loop 
FOR /F "tokens=1* delims=;" %%G IN (%string%) DO set line="%%G" & echo %line:"=% & set string="%%H"
if %string% NEQ "" goto :loop

3rd version:

@echo off
set string="%PATH%"
:loop
FOR /F "tokens=1* delims=;" %%G IN (%string%) DO CALL :sub "%%G" "%%H"
if %string% NEQ "" goto :loop
goto :eof

:sub
set line=%1
echo %line:"=%
set string=%2
carlos_lm
  • 523
  • 2
  • 5
  • 10
0

This works for me (just an extract from my whole script)

choice /C 1234567H /M "Select an option or ctrl+C to cancel"
set _dpi=%ERRORLEVEL%

if "%_dpi%" == "8" call :helpme && goto menu 

for /F "tokens=%_dpi%,*" %%1 in ("032 060 064 096 0C8 0FA 12C") do set _dpi=%%1
echo _dpi:%_dpi%:
gonzalezea
  • 472
  • 3
  • 7
-1

one more variation - this looks for the program "cmd.exe" in the current path and reports the first match:

@echo off
setlocal
setlocal enableextensions
setlocal enabledelayedexpansion

set P=%PATH%
:pathloop
for /F "delims=; tokens=1*" %%f in ("!P!") do (
    set F=%%f
    if exist %%f\cmd.exe goto found
    set P=%%g
)
if defined P goto pathloop

echo path of cmd.exe was not found!
goto end

:found
echo found cmd.exe at %F%
goto end

:end
alex
  • 111
  • 1
  • 11
  • Your answer has nothing to do with the question – jeb Dec 03 '14 at 13:41
  • the path variable is a joint string. splitting it up is done in the example. and a small operation is added that will demonstrate to everyone how real work can be done insided the parsing loop. this work example shows an "exit-on-first-hit" reaction. – alex Dec 10 '14 at 12:38