2

I don't know if its age or lack of practice. Either way I cannot wrap my head around this issue. I am trying to set a subroutine but the string that I am passing along are being split because of the space in string 3 and 4.

SET SubA=String1,String2,String 3,String 4
FOR %%A IN (%SubA%) DO MD "%%A"

I've tried parenthesis around the string The <> brackets like Microsoft says to use. I have also tried this line below without success.

setlocal enableDelayedExpansion
For /F "tokens=* delims=" %%A  IN (%Var%) DO  MD "%%A"

Also I would love if possible could I make an list, possibly with an array. Like in Power shell I could do this. I really need to keep in the same batch file so the user could edit the list. I am aware that I could use caret but the easier I can make it for my client the better.

$Folders (
String1
String2
String 3
String 4
)

Edit: My desired result is to have this script create a set of folders like those pictured. Desired Results

Compo
  • 36,585
  • 5
  • 27
  • 39
NoNo
  • 315
  • 1
  • 4
  • 13
  • 2
    As an alternate, you can just let Powershell handle the lifting for you: `powershell -command "'string1', 'string2', 'string 3', 'string 4' | Foreach-Object -Process { New-Item -Path C:\ -Name $_ -Type Directory }"` – Abraham Zinala Mar 29 '21 at 02:53
  • The problem with that it is part of a bigger script and moving this small section to ps wont work. – NoNo Mar 29 '21 at 04:18
  • 2
    quote (at least) the "spacy" arguments: `SET SubA=String1,String2,"String 3","String 4"` and use `md "%%~A"` to remove the quoutes again. – Stephan Mar 29 '21 at 07:09
  • 2
    @AbrahamZinala, if they could just rewrite it, there's no reason why they cannot do it like this in the first place, `Set "SubA=String1,String2,"String 3","String 4""`, and then create the directories like this, `For %%G In (%SubA%) Do MD %%G`; or as Stephan has mentioned, doublequote them all, `Set "SubA="String1","String2","String 3","String 4""`, then use `For %%G In (%SubA%) Do MD "%%~G"`. Either way, neither of those are as simple as the method I've included in my answer. – Compo Mar 29 '21 at 11:47
  • I still don't see how that one liner I offered would cause an issue to for them. Even if they wanted to create a separate array for that, its still possible: `Set Folders = string1, string2, "String 3", "String 4"`. Then, `powershell -command "%Folders% | Foreach-Object -Process { New-Item -Path C:\ -Name $_ -Type Directory }"`, its still all done in batch, its just calling Posh to do it for you. – Abraham Zinala Mar 29 '21 at 11:54
  • @Compo, also ran your simplest solution and it worked for me. Don't see why they cant set your post as the answer. – Abraham Zinala Mar 29 '21 at 12:00
  • @NoNo here is a really good answer on how to use arrays in a batch file: [Arrays, linked lists and other data structures in cmd.exe (batch) script](https://stackoverflow.com/a/10167990/1417694) – Squashman Mar 29 '21 at 12:52
  • Actually @AbrahamZinala, that would require modification, because, you've created a variable named `%Folder %`. Additionally, to speed up the much slower powershell command, you should probably use `-NoProfile` too, to prevent it having to load unnecessary things, thus slowing it still further. NoNo, if my solution has worked for you, could you please consider marking that answer as accepted. – Compo Mar 29 '21 at 13:59

3 Answers3

3

The simplest pure batch-file solution that doesn't require trickery is to use for's ability to enumerate space-separated tokens.

For this to work as intended, tokens that themselves contain spaces must be double-quoted:

@echo off & setlocal

:: Space-separated list of folder names, with names that contains
:: spaces themselves double-quoted.
SET SubA=String1 String2 "String 3" "String 4"

:: Loop over the list elements and create a directory for each.
FOR %%A IN (%SubA%) DO MD %%A

As Compo's helpful answer implies, you could actually pass this list to a single invocation of
MD: MD %SubA%


Unfortunately, as far as I know, batch files do not offer a convenient way to define lists in a one-item-per-line format.

However, you could provide the list of names via an external file, with each name on its own line (no double-quoting needed), which can then be parsed with for /f; e.g.:

@echo off & setlocal

:: Determine the full path of the file "names.txt" 
:: located in the same folder as this batch file.
set "nameList=%~dp0names.txt"

:: Loop over all names in the file and call `md` with each.
for /f "usebackq delims=" %%n in ("%nameList%") do md "%%n"

And input file names.txt would then contain something like:

String1
String2
String 3
String 4
mklement0
  • 382,024
  • 64
  • 607
  • 775
1

The simplest way to 'make' your directories is probably like this:

Set "SubA=String1,String2,String 3,String 4"
MD "%SubA:,=" "%" 2>NUL

As for working with the initial variable, and using it array like, you could do it like this:

@Echo Off & SetLocal EnableExtensions EnableDelayedExpansion

Set "SubA=String1,String2,String 3,String 4"

For /F "Delims==" %%G In ('"(Set Index[) 2>NUL"') Do Set "%%G="
Set "i=0"
Set "Index[!i!]=%SubA:,=" & Set /A i += 1 & Set "Index[!i!]=%"
(Set Index[) 2>NUL && Pause

Or you could do it like this:

@Echo Off & SetLocal EnableExtensions EnableDelayedExpansion

Set "SubA=String1,String2,String 3,String 4"

For /F "Delims==" %%G In ('"(Set Index[) 2>NUL"') Do Set "%%G="
Set "i=-1"
For %%G In ("%SubA:,=","%") Do (Set /A i += 1
    Set "Index[!i!]=%%~G")
(Set Index[) 2>NUL && Pause
Compo
  • 36,585
  • 5
  • 27
  • 39
  • 1
    I am unsure how to run this. I have run both scripts and it doesn't create any folders. I modified it a could of different ways by adding MD and a variable that was picked out of here and I could not get it to create any folders. – NoNo Mar 29 '21 at 02:32
  • @NoNo, I'm not sure why you mentioned arrays, if you don't know how to use each of its indexes. Anyhow, whilst you work out exactly what you needed those for, I've put the very basic answer, of how to just Make Directories, splitting the variable at each of the commas, _(and not the spaces)_. – Compo Mar 29 '21 at 10:50
0

Here is another way to create the directories using the PowerShell that is already on your system if it is still supported by Microsoft. When you are satisfied that the correct directories will be created, remove the -WhatIf from the mkdir command.

SET "SubA=String1,String2,String 3,String 4"
powershell -NoLogo -NoProfile -Command ^
    "'%SubA%'.split(',') | ForEach-Object { mkdir $_ -WhatIf | Out-Null }

A better way would be to test to see if the directory already exists before trying to create it.

SET "SubA=String1,String2,String 3,String 4"
powershell -NoLogo -NoProfile -Command ^
    "'%SubA%'.split(',') | ForEach-Object {" ^
        "if (-not (Test-Path -Path $_)) { mkdir $_ | Out-Null }" ^
    "}"
lit
  • 14,456
  • 10
  • 65
  • 119