Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch file variable scope issue

I'm having a strange variable scope issue when trying to create a 'dos' (windows 7 command line) batch file which performs a bit of string manipulation to create new file paths. Can anyone see why the OUTPUT_FILENAME variable always ends up being null in the example below?

echo Enter the Data Input, S (Site) or U (User)
set /p DATA_TYPE=
echo.
echo Enter the Input File Name
set /p INPUT_FILENAME=
echo.
IF /I %DATA_TYPE%==u (
  set OUTPUT_FILENAME=%INPUT_FILENAME:\users\=\Users\Outputs\%
  set OUTPUT_FILENAME=%OUTPUT_FILENAME:xls=txt%
  echo Output:
  echo %OUTPUT_FILENAME%
)
IF /I %DATA_TYPE%==s (
  set OUTPUT_FILENAME=%INPUT_FILENAME:\sites\=\Sites\Outputs\%
  set OUTPUT_FILENAME=%OUTPUT_FILENAME:xls=txt%
  echo Outputs:
  echo %OUTPUT_FILENAME%
)

Thanks in advance for any assistance, this is driving me nuts!

like image 918
user3241379 Avatar asked Jan 27 '14 17:01

user3241379


People also ask

Can you use variables in batch files?

There are two types of variables in batch files. One is for parameters which can be passed when the batch file is called and the other is done via the set command.

How do I set the global variable in a batch file?

Variable Scope (Global vs Local) In the batch script, we can create a local variable using the SETLOCAL command. The scope of the local variable only between the SETLOCAL and ENDLOCAL command and it is destroyed as soon as the ENDLOCAL statement is executed.

Why is %% used in batch file?

Use double percent signs ( %% ) to carry out the for command within a batch file. Variables are case sensitive, and they must be represented with an alphabetical value such as %a, %b, or %c. Required. Specifies one or more files, directories, or text strings, or a range of values on which to run the command.


2 Answers

You need to enable the delayed expansion:

setlocal EnableDelayedExpansion
echo Enter the Data Input, S (Site) or U (User)
set /p DATA_TYPE=
echo.
echo Enter the Input File Name
set /p INPUT_FILENAME=
echo.
SET OUTPUT_FILENAME=Empty
IF /I %DATA_TYPE%==u (
  set OUTPUT_FILENAME=!INPUT_FILENAME:\users\=\Users\Outputs\!
  set OUTPUT_FILENAME=!OUTPUT_FILENAME:xls=txt!
  echo Output:
  echo !OUTPUT_FILENAME!
)
IF /I %DATA_TYPE%==s (
  set OUTPUT_FILENAME=!INPUT_FILENAME:\sites\=\Sites\Outputs\!
  set OUTPUT_FILENAME=!OUTPUT_FILENAME:xls=txt!
  echo Outputs:
  echo !OUTPUT_FILENAME!
)

As the help for the SET command states:

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed.

So, you need to use the delayed expansion to make sure that INPUT_FILENAME OUTPUT_FILENAME's value are expanded at execution time.

like image 57
Laf Avatar answered Sep 28 '22 00:09

Laf


As Laf has correctly indicated, the code, as is, needs delayed expansion. In batch files, when a line or a block (all the lines enclosed in parenthesis) is reached, before being executed, it is parsed. In this parse phase, each variable read is replaced with the value the variable has before the execution starts.

If inside a block you change a variable, and want to access this changed value inside the same block, you need delayed expansion. The code in Laf answer reflect how to do it

Or, if it is possible, you can change your code to not need it

echo Enter the Data Input, S (Site) or U (User)
set /p DATA_TYPE=
echo.
echo Enter the Input File Name
set /p INPUT_FILENAME=
echo.
IF /I %DATA_TYPE%==u (
  set OUTPUT_FILENAME=%INPUT_FILENAME:\users\=\Users\Outputs\%
)
IF /I %DATA_TYPE%==s (
  set OUTPUT_FILENAME=%INPUT_FILENAME:\sites\=\Sites\Outputs\%
)
set OUTPUT_FILENAME=%OUTPUT_FILENAME:xls=txt%
echo Output:
echo %OUTPUT_FILENAME%

Now, there are variables changed inside blocks, but the values are then accessed out of the blocks.

like image 26
MC ND Avatar answered Sep 28 '22 00:09

MC ND