Clear all Environment variables

Hello everybody.

I am trying to clear all my environment variables.

I would do this:

var result = command ('env show').run(returnOutput = true);

var rows = DESerializeJSON(result);

for ( var item  in rows )  {
    command('env clear #item#').run();
}

But I can’t create a structure from the JSON returning from “env show”.

The mistake is

Syntax Error, Invalid Construct
at position 8 in [{[38; 5; 12m "db ...]

Is there another easier way to reset my environment variables?

Thank you! :heart:

@Roberto_Marzialetti If you’re doing this from a task runner or custom command, I wouldn’t run commands, I’d just interact directly with the systemSettings CFC that’s already injected for you.

But first, you need to be aware that the output of env show isn’t quite an exact representation of how the env vars are actually stored. Firstly, there is a hierarchy of env vars

  • “top level” env vars in the shell
  • env vars defined by the current running command’s context
  • env vars defined by the parent/calling command’s context
  • env vars defined by the parent/calling commands parent/calling command’s context
  • And so on, depending on how deep the call stack is

To visualize this, run the env debug command to see the full hierarchy, keeping in mind, an env var of the sme name can be defined more than once in different contexts. The “closest” context’s value is what you’ll see in the env show command. On this same note, the env clear command is ONLY going to clear an env var from the current command context, not from any parent contexts.

Secondly, keep in mind if you’re using the commandbox-dotenv module and running commands in a directory with an .env file, those env vars loaded from the file will just be loaded again on the next command. There are debugging settings you can enable in the dotenv module which will tell you every time it loads env vars into the current command’s context from an .env file.

So the first step is to use the env debug command to ensure where these env vars actually live.

Now, back to the SystemSettings class, instead of running env show, just run this to get the env vars in the current context:

var structOfVars = systemSettings.getCurrentEnvironment()

And instead of using env clear, just directly delete keys from that struct. It’s all passed by reference.

Or if you want to get the entire hierarchy shows in the env debug, run this:

var arrayOfEnvStructs = systemSettings.getAllEnvironments()

Now, just for completeness-- to explain why you got that error-- that’s because the JSON coming out of the built in functions has ANSI formatting in it. In order to make that work, you’d have needed to strip the ANSI first.

var rows = DESerializeJSON( print.unansi( result ) );

And finally, can you explain what you’re doing that requires you to be wiping all env vars? That seems like a curious use case, and the design of having a command-specific context is designed such that you can

  • run a command/task
  • load env vars within the context of that command/task
  • use the env vars just for that command/task
  • once the command/task ends, the context is destroyed and everything is left clean again
1 Like

Thank you very much @bdw429s!
You are always so precious and exhaustive in the explanations! :heart:

Thats great! Work good! :star_struck:
I find my vars env in “Global Shell” context.

I try with too:

var rows = DESerializeJSON( print.unansi( result ) );

and works fine too :smile:


But i want to tell you something more about my code.

I’m trying to port my old deployment system from Ant/Ivy to CommandBox, so some mechanisms must be similar.

For example, I have three files to consider for my environment variables, and these have a hierarchy.

Like this:

It starts with this:
/build/all-envs.properties

All variables written in the previous file can be overwritten by one of these files:
/build/envs/devel.properties

… lastly, this file can overwrite all previous variables:
/build/local-env.properties

If, for example, the variable “db.host” is both in all-envs.properties and in local.properties, I have to take the value present in local.properties.

I’m going ahead like this:

/build/Build.cfc

funcion deploy( env = "devel" ) {

    // my global file
    var mainConfig = "#dir#/build/all-envs.properties";

    // the environment file
    var envConfig = "#dir#/build/envs/#arguments.env#.properties";

    // the user's file
    var localConfig = "#dir#/build/local.properties";

    // I create a structure from current environment file
    var envItems = getStructFromEnvFile( envConfig );

    // I create a structure from the global env file
    var mainItems = getStructFromEnvFile( mainConfig );

    // I create a structure from the user's env file, if exists
    if (FileExists (localConfig)) {
        var localItems = getStructFromEnvFile( localConfig );
    }

    // merge of environment variables.
    // local.properies overrides every variable
    StructAppend (mainItems, envItems, true);
    StructAppend (mainItems, localItems, true);

    // delete .env file in webroot...
    if (FileExists  ("#dir#/.env")) {
       cffile (file = "#dir#/.env", action = "delete");
    }
    // ... than rewrite it with all env variables
    for (var item in mainItems) {
        cffile( file="#dir#/.env", action="append", output="#item# = #mainItems [item]#" );
    }

    // install dependencies
    command('install').run();

    // start the server
    command('server start').run();

}

i invoke this procedure from command line:

CommandBox:test-box> run-script deploy:devel

I add this line to my box.json
"deploy:devel": "task run taskFile=build/Build.cfc target=deploy :env=devel",

Ah, that’s simple enough.

In development, every time I launch my “run-script deploy:devel” I would like to reset the environment variables, because they are never reset even when I restart the server.

Do you have any advice for me?
Anything you tell me will be very precious.

Many thanks! :smile:

So I think you have made much more complicated than necessary the loading of the files. I do this as well for several projects, but all you need is the dotenv load command!

command( 'dotenv load' ).params( resolvePath( 'build/all-envs.properties' ) ).run();
command( 'dotenv load' ).params( resolvePath( 'build/envs/devel.properties' ) ).run();
command( 'dotenv load' ).params( resolvePath( 'build/local-envs.properties' ) ).run();

This will load all three property files in order, overwriting vars as needed. The resolvePath() is technically unecessary if you always run the task run command from the root of the project since the dotenv load command will treat relative paths as relative to the current working dir of the shell, but it’s a good idea since it will make those paths relative to the location of the task runner.

See, that’s just the thing-- if you use the code above, those env vars won’t be loaded into the global context, they will be loaded into the context of the current command (task run) which means they are automatically cleared when the command is finished. Now there is no need to clear them because they are automatically cleared for you!

1 Like