0

I am trying to pass 14 variables from one file to another in batch, but it stops working after the 9th one.

Here is the code that I used and the outputs.

Code of caller.bat:

@echo off
set vara=A
set varb=B
set varc=C
set vard=D
set vare=E
set varf=F
set varg=G
set varh=H
set vari=I
set varj=J
set vark=K
set varl=L
set varm=M
set varn=N

echo Variables set in caller.bat:
echo %vara%
echo %varb%
echo %varc%
echo %vard%
echo %vare%
echo %varf%
echo %varg%
echo %varh%
echo %vari%
echo %varj%
echo %vark%
echo %varl%
echo %varm%
echo %varn%

echo Calling passTo.bat
call passTo.bat %vara% %varb% %varc% %vard% %vare% %varf% %varg% %varh% %vari% %varj% %vark%  %varl% %varm% %varn%
pause>nul

Output of caller.bat:

Variables set in caller.bat:
A
B
C
D
E
F
G
H
I
J
K
L
M
N
Calling passTo.bat

Code of passTo.bat:

echo Inside passTo.bat
set vara=%1
set varb=%2
set varc=%3
set vard=%4
set vare=%5
set varf=%6
set varg=%7
set varh=%8
set vari=%9
set varj=%10
set vark=%11
set varl=%12
set varm=%13
set varn=%14
echo vara: %vara%
echo varb: %varb%
echo varc: %varc%
echo vard: %vard%
echo vare: %vare%
echo varf: %varf%
echo varg: %varg%
echo varh: %varh%
echo vari: %vari%
echo varj: %varj%
echo vark: %vark%
echo varl: %varl%
echo varm: %varm%
echo varn: %varn%

Output of passTo.bat:

Inside passTo.bat
vara: A
varb: B
varc: C
vard: D
vare: E
varf: F
varg: G
varh: H
vari: I
varj: A0
vark: A1
varl: A2
varm: A3
varn: A4

As it can be seen it messes up after the 9th one and it just starts adding numbers to the end of variables. I am doing this for myself to see if I can implement this to a randomizer to choose names.

Mofi
  • 46,139
  • 17
  • 80
  • 143
  • 1
    See `shift /?` for how. It's not straight forward. If needing random numbers see `set /?` at the end of help. – ACatInLove Jan 06 '18 at 04:03
  • where would i put shift /? – Tailsizkool Jan 06 '18 at 04:05
  • Read help and find out. You have to rewrite your code. – ACatInLove Jan 06 '18 at 04:08
  • I strongly suggest you to use an [array](https://stackoverflow.com/questions/10166386/arrays-linked-lists-and-other-data-structures-in-cmd-exe-batch-script/10167990#10167990), with variables in `set var[1]=A`, `set var[2]=B`, etc. form, instead of your `vara`, `varb`, etc. variables... – Aacini Jan 06 '18 at 04:30
  • 1
    you can iterate `%*` with for loop too. – npocmaka Jan 06 '18 at 04:42
  • 1
    you just need to copy the text output and put it here, no need to capture a screenshot – phuclv Jan 06 '18 at 05:32
  • @npocmaka: Yes, but the `for` iteration, or a `shift`-assembled loop, only makes sense if the receiving variables are array elements selected by a numeric index... – Aacini Jan 06 '18 at 05:55
  • PassTo,bat can read the variables and values set by caller.bat. Do you need to pass arguments if can you sync the 2 scripts to share the same variable names of interest? – michael_heath Jan 06 '18 at 06:20
  • @Aacini You are generalising solutions to particular problems. This is a problem in batch as its painfully slow. – ACatInLove Jan 06 '18 at 08:20
  • When you `Call` one script from another, the environment variables set within the calling script are maintained and useable in the called script. The examples you have posted appear to be completely unnecessary because the second script is defining variables which have already been defined in the first scriopt and available for use in script two. – Compo Jan 06 '18 at 13:07

2 Answers2

1

From shift /?:

C:\Users\iBug>shift /?
Changes the position of replaceable parameters in a batch file.

SHIFT [/n]

If Command Extensions are enabled the SHIFT command supports
the /n switch which tells the command to start shifting at the
nth argument, where n may be between zero and eight.  For example:

    SHIFT /2

would shift %3 to %2, %4 to %3, etc. and leave %0 and %1 unaffected.

So if you have, say 12 parameters, you can use 3 shift's. After that the original 1st and 2nd arguments will no longer be available (as well as %0), and the original 10th to 12th arguments will be available as %7, %8 and %9.

Sample code:

REM Filename: foo.bat
@ECHO OFF
ECHO %1 %2 %3 %4
SHIFT
SHIFT
SHIFT
ECHO %1 %2 %3 %4
ECHO %6 %7 %8 %9

Run it like this:

C:\Users\iBug>foo.bat a b c d e f g h i j k l
a b c d
d e f g
i j k l

C:\Users\iBug>

You can also preserve the first 8 arguments using the switch, and only discard the 9th argument every time:

SHIFT /8
iBug
  • 35,554
  • 7
  • 89
  • 134
0

Help on an internal command of cmd.exe can be get and read by opening a command prompt window and running help command or command /?. Try this out with help call or call /? and help for or for /? and help shift or shift /?.

Standard console applications like ping.exe or xcopy.exe in folder %SystemRoot%\System32 support also being executed with option /? to show help. Try it out with ping /?, choice /? or find /?. Those executables are also known as external commands as available by default on Windows (depending on Windows version), but not being internal commands of cmd.exe.

Here is code of caller.bat with some really ugly strings to pass:

@echo off
setlocal
set "vara="""
set "varb=B"
set "varc="C""
set "vard=Hello!"
set "vare="%%PATH%%""
set "varf=F"
set "varg=G"
set "varh=Operators: &()[]{}^=;!'+,`~<>|"
set "vari=I"
set "varj=J"
set "vark=K"
set "varl=!PATHEXT!"
set "varm=M"
set "varn=N"

cls
echo Variables set in %~nx0:
echo/
set var
echo/
echo Calling passTo.bat
echo/
setlocal EnableDelayedExpansion
call passTo.bat %vara%  %varb% %varc% !vard! !vare! %varf% %varg% "!varh!" %vari% %varj% %vark% "!varl!" %varm% %varn%
endlocal
endlocal

The output of this batch file is:

Variables set in caller.bat:

vara=""
varb=B
varc="C"
vard=Hello!
vare="%PATH%"
varf=F
varg=G
varh=Operators: &()[]{}^=;!'+,`~<>|
vari=I
varj=J
vark=K
varl=!PATHEXT!
varm=M
varn=N

Calling passTo.bat

And here is code of passTo.bat with three methods to process passed arguments.

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Is this batch file called with at least 1 argument string?
if not "%~1" == "" goto MainCode
rem It can be even an empty argument string, i.e. just "".
if #%1 == #"" goto Maincode
echo %~nx0 is called with no argument.
goto EndBatch


rem ArgumentToVariable is a subroutine called from FOR loop below.
:ArgumentToVariable
call set "Letter=%%Indices:~%Index%,1%%
set var%Letter%=%1
set /A Index+=1
goto :EOF


:MainCode
echo Inside %~nx0 executed with the arguments:
echo %*
set "Index=0"
set "Indices=abcdefghijklmn"

for %%I in (%*) do call :ArgumentToVariable %%I

echo/
echo Arguments list processed with command FOR with using a subroutine:
echo/
set var
rem End current local environment to discard all environment variables.
endlocal


rem Setup a new local environment to recreate all variables once again.
setlocal EnableExtensions EnableDelayedExpansion
set "Index=0"
set "Indices=abcdefghijklmn"

for %%I in (%*) do (
    set "Letter=Indices:~!Index!,1"
    call set "Letter=%%!Letter!%%"
    set var!Letter!=%%I
    set /A Index+=1
)

echo/
echo Arguments list processed with command FOR with using delayed expansion:
echo/
set var
rem End current local environment to discard all environment variables.
endlocal

rem Setup a new local environment to recreate all variables once again.
setlocal EnableExtensions DisableDelayedExpansion
set "Index=0"
set "Indices=abcdefghijklmn"

:ShiftLoop
call set "Letter=%%Indices:~%Index%,1%%
set var%Letter%=%1
set /A Index+=1
shift
if not "%~1" == "" goto ShiftLoop
if #%1 == #"" goto ShiftLoop

echo/
echo Arguments list processed with command SHIFT:
echo/
set var

:EndBatch
endlocal

echo/
echo Variables list as defined by parent batch file:
echo/
set var

And the output of passTo.bat is:

Inside passTo.bat executed with the arguments:
""  B "C" Hello! "C:\Windows\System32;C:\Windows;C:\Windows\system32\wbem" F G "
Operators: &()[]{}^^=;!'+,`~<>|" I J K "!PATHEXT!" M N

Arguments list processed with command FOR with using a subroutine:

vara=""
varb=B
varc="C"
vard=Hello!
vare="C:\Windows\System32;C:\Windows;C:\Windows\system32\wbem"
varf=F
varg=G
varh="Operators: &()[]{}^^^^=;!'+,`~<>|"
vari=I
varj=J
vark=K
varl="!PATHEXT!"
varm=M
varn=N

Arguments list processed with command FOR with using delayed expansion:

vara=""
varb=B
varc="C"
vard=Hello\Windows\System32
vare=C:\Windows
varf=C:\Windows\system32\wbem" F G "Operators:
varg=&()[]{}
varh=PATHEXT" M N
vari=I
varj=J
vark=K
varl=!PATHEXT!
varm=M
varn=N

Arguments list processed with command SHIFT:

vara=""
varb=B
varc="C"
vard=Hello!
vare="C:\Windows\System32;C:\Windows;C:\Windows\system32\wbem"
varf=F
varg=G
varh="Operators: &()[]{}^^=;!'+,`~<>|"
vari=I
varj=J
vark=K
varl="!PATHEXT!"
varm=M
varn=N

Variables list as defined by parent batch file:

vara=""
varb=B
varc="C"
vard=Hello!
vare="%PATH%"
varf=F
varg=G
varh=Operators: &()[]{}^=;!'+,`~<>|
vari=I
varj=J
vark=K
varl=!PATHEXT!
varm=M
varn=N

It can be seen on comparing the lists that some argument strings are not passed unmodified from batch file caller.bat to passTo.bat via arguments list.

The best result is produced by the method using command SHIFT on passing strings via arguments to another batch file. But the really best solution is passing strings from one batch file to another one using environment variables as shown by last variables list being identical to output of caller.bat because of passTo.bat outputs the environment variables defined by parent batch file.

All three methods work well on parsing simple strings like file name strings enclosed in double quotes and not containing % or ! or ^ via arguments list.

And using a variable naming scheme like var_1, var_2, ... or var[1], var[2], ... would make arguments and variables processing definitely easier because integer numbers can be easily incremented while getting next letter from a list is more difficult to achieve.

See also Copy text from a Windows CMD window to clipboard.

Mofi
  • 46,139
  • 17
  • 80
  • 143