できない.dev

環境変数を読むには

各言語で環境変数を読み取る基本形を示す。
未設定のときに既定値を与える書き方と、値が常に文字列で返る点への注意までを扱う。

公開: 更新:

選んだ言語は、ほかのサンプルコードを開いたときも最初に表示する。

Python

import os
 
print(os.environ["PATH"])            # 未設定だと KeyError
print(os.environ.get("PORT", "3000"))  # 無ければ既定値
port = os.getenv("PORT", "3000")       # getenv も同じ意味

os.environ["KEY"] は未設定だと KeyError を投げる。
落としたくないときは get や os.getenv に既定値を渡す。
値は常に文字列で返るため、数値として使うなら int() で変換する。

JavaScript

const port = process.env.PORT ?? "3000"; // 未設定なら既定値
console.log(process.env.PATH);            // 値は文字列 or undefined

Node.js では環境変数は process.env にまとまっており、未設定のキーは undefined になる。
?? や || で既定値を補う。
ブラウザには process が無く、Vite なら import.meta.env のようにバンドラが置き換える仕組みを使う。

できないときVite で環境変数(import.meta.env)が読み込めないできないときVite「process is not defined」の原因と直し方できないときnpm scripts で環境変数が設定できない(Windows で動かない)

TypeScript

const port: string = process.env.PORT ?? "3000";
// process.env.KEY の型は string | undefined

process.env のプロパティは string | undefined 型なので、未設定を考慮せず string として使うと型エラーになる。
?? で既定値を与えるか、事前に存在を確認して絞り込む。
型定義には @types/node が要る。

Go

package main
 
import (
	"fmt"
	"os"
)
 
func main() {
	port := os.Getenv("PORT") // 未設定でも空でも空文字
	if port == "" {
		port = "3000"
	}
	fmt.Println(port) // PORT=8080 なら 8080、未設定や空なら 3000
	if v, ok := os.LookupEnv("PORT"); ok {
		fmt.Printf("PORT は設定済み: %q\n", v) // 空文字で設定したときも ok は true
	}
}

os.Getenv は未設定でも空文字を返すだけでエラーにならず、空文字で設定された場合と区別できない。
区別したいときは os.LookupEnv を使い、第 2 戻り値の ok で存在を判定する(空文字で設定したときも ok は true になる)。

Rust

use std::env;
 
fn main() {
    // 未設定なら Err を返すので既定値でフォールバック
    let port = env::var("PORT").unwrap_or_else(|_| "3000".to_string());
    println!("{port}"); // PORT=8080 なら 8080、未設定なら 3000
}

std::env::var は環境変数が無い場合や不正な UTF-8 の場合に Err を返す Result 型である。
未設定でも落とさないよう unwrap_or_else などで既定値を用意するが、空文字で設定されているときは Ok("") になって既定値は使われないので、空を未設定扱いにしたいなら取得後に自分で判定する。

Java

public class Main {
    public static void main(String[] args) {
        String port = System.getenv("PORT");
        if (port == null) port = "3000"; // 未設定は null
        System.out.println(port);
    }
}

System.getenv は未設定の環境変数に対して null を返すため、そのまま使うと NullPointerException の原因になる。
null チェックで既定値を補うか、Optional でラップして扱う。

C#

using System;
 
class Program {
    static void Main() {
        // 未設定なら null
        string port = Environment.GetEnvironmentVariable("PORT") ?? "3000";
        Console.WriteLine(port); // PORT=8080 なら 8080、未設定なら 3000
    }
}

Environment.GetEnvironmentVariable は未設定のとき null を返す。
?? 演算子で既定値を与えると未設定でも安全に扱える。
ユーザー単位やマシン単位を指定する第 2 引数の EnvironmentVariableTarget は Windows の仕組みで、Linux では Process 以外を指定すると、変数があっても null が返る。

つまずき

環境変数が読めない原因の多くは、コードの書き方ではなく「そのプロセスに変数が渡っていない」ことにある。
シェルで export したのに別ターミナルで実行した、.env ファイルを読み込むライブラリを通していない、といったケースが典型である。
まずは一時的に値を出力して、そもそも渡っているかを確認する。

未設定のときの既定値

どの言語でも未設定の扱いは分かれる。
Python の os.environ[] や Java の getenv は「未設定」を KeyError や null で表し、Go の os.Getenv は空文字を返す。
想定外の落ち方を避けるため、get の既定値引数や ?? 演算子、LookupEnv の存在フラグで必ずフォールバックを用意する。

空文字で設定されているとき

空文字で設定された変数は「設定済み」として扱われ、未設定向けの既定値は使われない。
Rust の env::var は Ok("") を、C# の GetEnvironmentVariable は空文字を返す(どちらも Linux コンテナで実測)。
Go は os.Getenv の結果を空文字と比べるので未設定でも空でも既定値になるが、LookupEnv の ok は空で設定したときも true になる。
空を未設定と同じに扱うかどうかは、読む側で決めておく。

このコードで動いた?