# 在不同的作業系統下如何設定包含小數點的環境變數名稱

一般來說，我們極少會在環境變數上使用**小數點**( `.` )當成**環境變數名稱**來使用，但是在特定應用程式的條件下，可能被迫需要做出這樣的設定。像透過環境變數設定 .NET 應用程式的 `LogLevel` 就很可能會用到小數點來進行設定，本篇文章我將說明不同作業系統下的設定方式與潛在問題。

### 前情提要

假設我們已經安裝好 [.NET 6 SDK](https://dot.net/download) 並用以下命令建立一個 Web 應用程式：

```bash
dotnet new web -n web1
```

你可以從 `web1\appsettings.json` 檔案看到以下內容：

```json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
```

因為 .NET 預設會透過 `EnvironmentVariablesConfigurationProvider` 載入**環境變數**，作為應用程式的組態，當我們將 .NET 執行在容器中或跑在 IIS 的時候，都很容易設定環境變數來設定應用程式組態。

例如我們在應用程式執行前設定 `Logging__LogLevel__Default` 環境變數，將其值設定成 `Warning`，就可以讓整個 .NET 應用程式**預設**所有 `LogLevel` 為 `Warning` 等級以上，這個等級以下的就不會輸出到記錄中。

不過，另外還有一個 `Microsoft.AspNetCore` 所代表的是另一個**記錄類別** (Log Category)，通常這裡所代表的是**命名空間** (namespace)，因為預設透過 `ILogger<T>` 注入的物件，預設**記錄類別**就是型別的**完整名稱** (Full Name)，也就是 **命名空間** (Namespace) 加上 **型別名稱** (Type Name)。由於 .NET 的命名空間都包含了小數點，因此你若要透過環境變數設定該參數，就一定會用到**小數點**當作**環境變數名稱**的一部分。

> 詳細內容請見 [Logging in .NET Core and ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-6.0) 文件說明。

### 問題說明與解決方案

這裡最主要的問題就是：

1.  Windows 環境變數允許出現 `.` (小數點) 符號
2.  Linux/macOS 的 Bash 殼層環境不允許出現 `.` (小數點) 符號

以下我就來說說不同作業系統的設定方法：

1.  Windows
    
    在 Windows 作業系統下，**環境變數名稱**是**允許小數點**的，因此設定上其實沒啥問題！
    
    以下是 PowerShell 的設定方法：
    
    ```powershell
    ${env:Logging__LogLevel__Microsoft.Hosting.Lifetime}='Debug'
    ```
    
    以下是 Command Prompt 的設定方法：
    
    ```batch
    set Logging__LogLevel__Microsoft.Hosting.Lifetime=Debug
    ```
    
2.  Linux / macOS
    
    如果你去看 Bash 的說明手冊 ( `man bash` )，會查到以下說明：
    
    > A word consisting only of **alphanumeric characters** and **underscores**, and beginning with an alphabetic character or an underscore. Also referred to as an identifier.
    
    簡言之，你完全無法在 Bash 環境下設定出一個含有 `.` (小數點) 的環境變數名稱，就是不可能！但有少數 Shell 環境是可以的，例如有個我自己也沒用過的 `rc` shell！
    
    但是你可以在應用程式啟動之前，透過 `env` 工具設定出一個臨時的、含小數點的環境變數，這是在 Linux / macOS 底下唯一可以使用的方法了。以下範例：
    
    ```bash
    env "Logging__LogLevel__Microsoft.AspNetCore=Trace" dotnet run
    ```
    

### 期待 .NET 7 解決這個問題

由於到了 .NET 6 都還沒有 `.` (小數點) 字元的替代命名規則，因此目前尚無法徹底解決 Bash 無法設定名稱中帶 `.` (小數點) 的環境變數。不過這個問題早在 2019 年就有人提出了，預計會在 .NET 7 的時候得到解決。詳見: [\[Feature Request\] Add a replacement for dot in EnvironmentVariablesConfigurationProvider #35989](https://github.com/dotnet/runtime/issues/35989)

### 相關連結

-   [Logging in .NET Core and ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-6.0)
-   [extensions/EnvironmentVariablesConfigurationProvider.cs at 192abfdf3e73106e40d7651eecfb621e4f78c344 · dotnet/extensions](https://github.com/dotnet/extensions/blob/192abfdf3e73106e40d7651eecfb621e4f78c344/src/Configuration/Config.EnvironmentVariables/src/EnvironmentVariablesConfigurationProvider.cs#L67-L70)
-   [\[Feature Request\] Add a replacement for dot in EnvironmentVariablesConfigurationProvider #35989](https://github.com/dotnet/runtime/issues/35989)
    -   [LogLevel Filter by Category may be not working on Linux (AppServices) when dots in CategoryName are replaced by underscore #60534](https://github.com/dotnet/runtime/issues/60534)
-   [Bug: Can't set Logging:LogLevel:Default via environment #3095](https://github.com/dotnet/extensions/issues/3095)
    -   [It's unclear how to handle a '.' in an environment variable configuration value. #17378](https://github.com/dotnet/AspNetCore.Docs/issues/17378)
    -   [Setting configuration variables with dots in names via env vars in Linux #1171](https://github.com/dotnet/extensions/issues/1171)
-   [Exporting a variable with dot (.) in it - Unix & Linux Stack Exchange](https://unix.stackexchange.com/a/93557/288400)
