Rust LogoWorking with Environment Variables

Environment variables are dynamic named values that can affect the way running processes behave on a computer. They are essentially key-value pairs stored in the operating system's environment, accessible by any program executing within that environment. Common uses include:

1. Configuration: Storing application settings (e.g., database connection strings, API keys, logging levels) that can vary between different deployment environments (development, staging, production) without altering the application's source code.
2. Paths: Defining directories where executable programs or libraries are located (e.g., `PATH` variable).
3. Secrets Management: Providing sensitive information like API keys, database credentials, or secret keys to applications without hardcoding them, enhancing security.
4. Feature Toggles: Enabling or disabling certain application features based on environment settings.

In Rust, interaction with environment variables is primarily handled by the `std::env` module. This module provides functions to read, set, and remove environment variables for the current process.

Key functions in `std::env`:

* `std::env::var(key: &str) -> Result<String, VarError>`:
* Attempts to retrieve the value of the environment variable named `key`.
* Returns `Ok(value)` if the variable is found and its value is valid Unicode.
* Returns `Err(VarError::NotPresent)` if the variable is not set.
* Returns `Err(VarError::NotUnicode)` if the variable's value contains invalid Unicode.
* `std::env::vars() -> Vars`:
* Returns an iterator over all environment variables for the current process.
* Each item yielded by the iterator is a tuple `(String, String)` representing a key-value pair.
* `std::env::set_var(key: &str, value: impl AsRef<OsStr>)`:
* Sets the environment variable `key` to `value` for the current process.
* This change only affects the current process and any child processes it spawns. It does *not* modify the system-wide environment variables permanently.
* `std::env::remove_var(key: &str)`:
* Removes the environment variable `key` for the current process.
* Similar to `set_var`, this change is local to the current process and its children.

Important Considerations:
* Security: Never log sensitive environment variables directly. Use them and dispose of them carefully.
* Scope: `set_var` and `remove_var` only affect the current process and its children. They do not alter the system-wide environment.
* Cross-Platform: While `std::env` functions are cross-platform, the actual names and common uses of environment variables can differ between operating systems (e.g., `HOME` on Unix-like vs. `USERPROFILE` on Windows).
* Error Handling: Always be prepared for an environment variable not to be set using `var()`, by handling the `VarError::NotPresent` case.

Example Code

use std::env;

fn main() {
    println!("--- Reading Environment Variables ---");

    // 1. Read a common environment variable (e.g., PATH)
    match env::var("PATH") {
        Ok(val) => println!("PATH: {}", val),
        Err(e) => println!("Couldn't read PATH: {}", e),
    }

    // 2. Read a variable that might not exist and handle the error
    match env::var("NON_EXISTENT_VAR") {
        Ok(val) => println!("NON_EXISTENT_VAR: {}", val),
        Err(e) => println!("NON_EXISTENT_VAR was not found or an error occurred: {}", e),
    }

    // 3. Set a new environment variable for the current process
    println!("\n--- Setting and Removing Environment Variables ---");
    let my_var_key = "MY_CUSTOM_VAR";
    let my_var_value = "Hello Rust Environment!";

    println!("Setting {}=\"{}\"", my_var_key, my_var_value);
    env::set_var(my_var_key, my_var_value);

    // 4. Read the newly set variable
    match env::var(my_var_key) {
        Ok(val) => println!("{} is now: {}", my_var_key, val),
        Err(e) => println!("Error reading {}: {}", my_var_key, e),
    }

    // 5. Update an existing environment variable
    let updated_value = "Updated value!";
    println!("Updating {} to \"{}\"", my_var_key, updated_value);
    env::set_var(my_var_key, updated_value);
    println!("{} is now: {}", my_var_key, env::var(my_var_key).unwrap());


    // 6. Remove the environment variable
    println!("Removing {}", my_var_key);
    env::remove_var(my_var_key);

    // 7. Try to read the removed variable (should fail)
    match env::var(my_var_key) {
        Ok(val) => println!("{} (after removal): {}", my_var_key, val),
        Err(e) => println!("{} was successfully removed (or not present): {}", my_var_key, e),
    }

    // 8. Iterate over all environment variables
    println!("\n--- All Environment Variables ---");
    for (key, value) in env::vars() {
        // We'll print only a few to avoid overwhelming the output
        if key.starts_with("RUST") || key == "PATH" || key == "HOME" || key == "USER" || key == "TEMP" {
            println!("{}: {}", key, value);
        }
    }
    println!("(Displayed a subset of all environment variables for brevity)");
}