challenge 環境変数の取得

コマンドライン引数の取得がありましたが、今回は環境変数の取得をお願いします。

取得した内容を表示できればよいですが、可能でしたらキーから値を得る手段の実装もお願いします。

Posted feedbacks - Nested

Flatten Hidden

つまらない回答ですが。

1
2
3
4
5
#! /usr/bin/perl

foreach(sort keys %ENV){
        print "$_: $ENV{$_}\n";
}

環境を選ぶかもしれません。

環境変数名=値

という文字列の配列なので、strtokで分割。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[], char *envp[])
{
    char **p;
    char *name;
    char *value;

    for(p = envp; p != NULL; p++) {
        name  = strtok(*p, "=");
        value = strtok(NULL, "=");
        printf("%s = %s\n", name, value);
    }

    return 0;
}
ども、raynstardです。
環境には依存しないと思いますが、
入力データを壊してしまうので基本的に直接strtok()は、
まずいいんじゃないでしょうか?
# forkとかexec*したときとか

このコードなら問題ないからやっているだけかもしれませんが。。。
ちょっと気になりました。
はい、envpはANSI Cでは規定されていないので、実装されていない処理系があることを想定したほうが良いと思います。というわけで<stdlib.h>のgetenv関数を使いました。ただし、こちらは名前から引くことしかできません。 なお、該当する名前の環境変数がなければNULLを返すので、条件演算子で振り分けています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    if (argc > 1)
    {
        const char* env = getenv(argv[1]);
        printf("$%s = %s\n",
            argv[1], env ? env
                         : "(none)");
    }
}

Sys.getenv() で名前つきvectorの形式で環境変数の一覧を取得できます。

引数にキーを指定すると、特定の値のみを取得することもできます。

1
2
3
4
5
6
# 1. get all environment variables
Sys.getenv()
# 2. get all keys of environment variables
names(Sys.getenv())
# 3. get a specific environment variable
Sys.getenv("PATH")

もっともシンプルな例だと思います。

getEnvironmentは(環境変数名, 値)というペアのリストを返します。

printはリストをそのままプリントアウトすることができます。

1
2
3
import System.Environment

main = getEnvironment >>= print

ついでにC++とQtで。 QMapを返すものがあるのかとおもい、探してみましたけど、検索能力が低く、見つけることができませんでした。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <QtCore>
#include <QtDebug>

#include <cstdlib>

int main(void)
{
        QStringList env = QProcess::systemEnvironment();
        QStringListIterator itr(env);
        QMap<QString, QString> envMap;
        while(itr.hasNext()) {
                QString str = itr.next();
                envMap[str.section('=', 0, 0)] = str.section('=', 1, 1);
        }

        qDebug() << envMap["PATH"];

        return EXIT_SUCCESS;
}
特にコメントなし、 誰が書いてもこんな感じでしょう。
1
2
3
System.getenv().each {
    println it
}

単純に。

1
(for-each print (sys-environ))
分かる範囲で対応してみました。
環境変数の取得に関しては、処理系依存ですが、大概の処理系には存在していて、統一的に扱えるようなラッパーのパッケージも存在しています。
環境変数一覧は、SBCL、CMUCL、Clozure CL、CLISP、Allegro CLに対応しています。
変数名からの値の取得は、SBCL、CMUCL、Clozure CL、CLISP、Allegro CL、ECL、LispWorksに対応しています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
(asdf:oos 'asdf:load-op :arnesi)
(asdf:oos 'asdf:load-op :osicat)

(defpackage :doukaku-191 (:use :cl))
(in-package :doukaku-191)

;; 一覧
(defun env ()
  #+(or sbcl cmu openmcl) (osicat:environment)
  #+clisp (getenv)
  #+allegro (excl.osi:environment))

;; 変数名から値を取り出し
(defun getenv (name)
  #+ecl (sys:getenv name)
  #-ecl (arnesi:getenv name))
1
2
3
4
5
6
rem 環境変数の一覧を表示
set
rem 値の取得
echo USERNAME=[%USERNAME%]
rem ついでに設定
set FOO=bar

System.getenv メソッドで環境変数が取得できます。引数にキーを渡した場合は対応する文字列が、キーを指定しない場合は Map 型で全ての環境変数が返されます。

1
2
3
4
5
6
7
public class Sample {

    public static void main(String[] args) {
        System.out.println(System.getenv());
        System.out.println(System.getenv("USER"));
    }
}

 RubyではENVオブジェクトを使用して参照します。

1
2
3
4
5
#! /usr/bin/ruby

ENV.keys.sort.each do |key|
    puts "#{key}:\t#{ENV[key]}"
end

ghcを使ってコマンドラインからワンライナーで。

1
% ghc -e "System.Environment.getEnvironment"

PHPは$_ENVで環境変数を扱います。

1
2
3
4
5
<?php

foreach( $_ENV as $key => $val ) {
    echo $key.': '.$_ENV[$key].PHP_EOL;
}

Pythonでは、環境変数はos.environという辞書 (連想配列) でアクセスできます。

1
2
3
4
5
6
7
8
9
import os

# 辞書の全要素を順番に読み出し。
# kには変数名、vにはその値が入る。
for k, v in os.environ.iteritems():
    print k, v

# キーを指定して読み出し。
print os.environ["PATH"]

http://ja.doukaku.org/comment/6777/ をもとに、もうちょっと突っ込んで調べてみました。

getも不要のようですね。

1
2
3
4
5
6
7
// 一覧
System.env.each {
    println it
}

// 1件
System.env["USERNAME"]
D 2.0 + 標準ライブラリ (Phobos)、Linuxで動作確認。連想配列を作ってしまう方針で。
Phobosには環境変数APIが無いので、Cの environ(7) を直接呼び出します。
C文字列をDのstringに変換する処理が面倒ですね。もっとうまいやり方があるような気がする...
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import std.stdio;
import std.string;
import std.c.linux.linux: environ;
import std.c.string: strlen;

void main()
{
    char** p;
    string[string] envAA;
    for (p = environ; *p != null; p++) {
        char[] key_and_value = (*p)[0 .. strlen(*p)];    // "FOO=BAR"
        int iEqual = key_and_value.find('=');    // index to '='
        string key = cast(string)(key_and_value[0 .. iEqual]);
        string value = cast(string)(key_and_value[iEqual + 1 .. $]);
        envAA[key] = value;
    }
    envAA.rehash;

    foreach(key, value; envAA) {
        writefln("%s: %s", key, value);
    }
    writefln("PATH = %s", envAA["PATH"]);
}
System.Environment.GetEnvironmentVariableメソッドで指定したキーの環境変数の値を取得出来ます。
System.Environment.GetEnvironmentVariablesメソッドで環境変数のキーと値がペアになったSystem.Collections.IDictionaryを取得出来ます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using System;

class Program {
    static void Main(string[] args) {
        //キーから取得
        Console.Write("環境変数を取得します。キーを入力して下さい。:");
        string key = Console.ReadLine();
        Console.WriteLine(Environment.GetEnvironmentVariable(key));

        //一覧を表示
        Console.Write("環境変数の一覧を表示します。");
        Console.ReadLine();
        foreach(string key_ in Environment.GetEnvironmentVariables().Keys) {
            Console.WriteLine("{0} = {1}", key_, Environment.GetEnvironmentVariables()[key_]);
        }
        Console.ReadLine();
    }
}
windows 用のコンソール版の場合です。
個々の環境変数は getenv で取得できるようですが、環境変数全体を
取得する方法が、わかりませんでした。存在しない変数名を指定すると
0 が返ります。
1
exit echo getenv 'tmp'
環境変数はosモジュールで提供されています。
Keyは引用符でくくった文字列を指定します。
1
2
3
4
5
%%全環境変数の表示
os:getenv().

%% キーを指定した場合
os:getenv(Key).

変数名から値を得るだけなら、getenv 関数があります。

1
2
3
4
5
private import std.stdio, std.process;

void main() {
    writeln(getenv("PATH"));
}
なでしこには「環境変数取得」「環境変数展開」の二つが標準命令にあります。
1
2
"PATH"の環境変数取得して表示
"%TMP%"の環境変数展開して表示

親OS上の環境変数の取得ということで、GhostScript 依存の getenv operator を使用しました。 PostScript の本来の環境変数(デバイス解像度等)は普通に currentdict 中に入っているわけで、普通に変数名だけで参照できるわけですが、マクロ等も一緒に入っているのでいわゆる変数一覧、というのは 膨大になると思います。後半のようにうっかり forall を使ってアクセスするとスタックがあふれたりとか....

1
2
3
4
5
6
7
%!PS

(PATH) getenv { = } if

% ========= Cut Here ===========
%!PS
currentdict { === } forall

env: ドライブを ls します。 ls は Get-ChildItem のエイリアスですので Get-ChildItem と書くほうがよいですね。 キーを指定する場合には env: ドライブのキーの項目を Get-Item します。

1
2
3
Get-ChildItem env:

Get-Item env:HOME
キーから値を得るにはSys.getenvを使う。
環境変数を全部取得するにはUnix.environmentを使う。
ちょっと紛らわしいけど、Unix.environmentはWindowsやcygwin環境でも使える。
以下のコードをコンパイルするには
$ ocamlc unix.cma hogehoge.ml
または
$ ocamlopt unix.cmxa hogehoge.ml
のようにunix.cma,unix.cmxaも一緒にコンパイルする必要がある。
1
2
3
4
5
(* show path *)
let v = Sys.getenv "PATH" in print_string v;;

(* show all enviroments *)
let e = Unix.environment () in Array.iter (Printf.printf "%s\n") e;;

Squeak Smalltalk で。

特定の値を得るには、返値に対してキーを指定してアクセス(#at:)します。

例: UnixProcess env at: #HOME

1
UnixProcess env

jclを使ってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import    scala.collection.jcl.Conversions

object PrintEnv {
    def printEnv:Unit = {
        Conversions.convertMap(System.getenv).keys.toList.sort { (a,b) => a < b }.foreach { k => printEnv(k) }
    }
    def printEnv(key:String):Unit = {
        Console.printf("%s:\t%s\n", key, System.getenv(key))
    }
    def main(args:Array[String]):Unit = {
        PrintEnv.printEnv
    }
}

 JavaFXScriptで。

1
2
3
4
5
import    java.lang.System;

for (k in System.getenv().keySet()) {
    System.out.printf("%s\t%s\n",k,System.getenv(k));
}
表示できればよいとの事なので、見やすさは考慮しません :-D
1
print %ENV;

bashで、exportされてないシェル変数を避けて環境変数の一覧を表示する方法には「printenv」「env」「export -p」があります。このうちexportはbash内蔵コマンドです。

特定のキーから環境変数の値を得るには、printenvに環境変数名を与えます。

蛇足として、内蔵コマンドだけで「printenv 変数名」相当のことをするコマンド(関数)を定義してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 環境変数一覧は以下のどれかで
printenv
env
export -p

# キーから値を得るには、printenvで
prinetnv 'HOME'

# printenvは外部コマンドだからという方には、pure bashで
myprintenv1() {
    local name=$1
    local a b str
    export -p | while read a b str;do
        if [ ${str%%=*} = "$name" ];then
            str=${str#*=\"}
            echo ${str%\"}
            break
        fi
    done
}
1
2
3
4
5
(* show path *)
case OS.Process.getEnv "PATH" of
   SOME v => print (v ^ "\n")
 | NONE => print "no path\n"
;

エラー処理つき。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import scala.collection.jcl.Conversions
object Env{
  val env = Conversions.convertMap(System.getenv)
  def apply(k:String):Option[String] = {
    try{
      Some(env(k))
    }catch{
      case _ => None
    }
  }
  def enum( f:(String,String)=>Unit ) : Unit = for( (k,v)<-env ) f(k,v)
}

object PrintEnv {
  def main(args : Array[String]) : Unit = {
     Env.enum{(k,v)=>println(k+" = "+v)}
     
     Env("SystemRoot") match {
       case Some(s) => println(s)
       case _ => println("!!!!!ERROR!!!!!!")
     }
     
     Env("SystemLoot") match {
       case Some(s) => println(s)
       case _ => println("!!!!!ERROR!!!!!!")
     }
     
     ()//result
  }
}
Envをfor文対応にしてみる。
for((k,v)<-Env) println(k+" = "+v)
というように。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
object Env extends Iterable[(String,String)]{
  val env = Conversions.convertMap(System.getenv)
  def apply(k:String):Option[String] = {
    try{
      Some(env(k))
    }catch{
      case _ => None
    }
  }
  override def elements : Iterator[(String,String)] = env.elements
}
WSHのJScriptです。WSHでは、WScript.Shellオブジェクトから取得可能です。
1
2
3
4
5
6
7
sh = new ActiveXObject('WScript.Shell');
env = sh.Environment;
stdIn = WScript.StdIn;
stdOut = WScript.StdOut;
stdOut.WriteLine('キー名を指定してください');
key = stdIn.ReadLine();
stdOut.WriteLine('%' + key + '% == ' + env(key));
今度は環境変数の一覧を取得する例です。こちらはVBScriptにしました。COMオブジェクトでの列挙操作は、VBScriptのほうがFor Eachが使えるので楽です。
1
2
3
4
5
6
7
8
Set sh = CreateObject("WScript.Shell")
Set env = sh.Environment

For Each e In env
    s = s & e & vbNewLine
Next

WScript.Echo s
VB.NETはC#との差別化が難しいですが、今回はMyを使ってC#と別物にできました。キーが見付からないと例外を投げるので、Catchで捕まえています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Module Env
    Sub Main()
        Console.WriteLine("キーを入力してください。")
        Dim key = Console.ReadLine()
        Try
            Console.WriteLine("%" & key & "% == " _
                & My.Application.GetEnvironmentVariable(key))
        Catch e As Exception
            Console.Error.WriteLine("キーの取得に失敗しました")
        End Try
    End Sub
End Module
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "mod_getenv.as"

#define IDW_MAIN 0
#define true 1
#define false 0

    gosub *LInitialize
    gsel IDW_MAIN, 1
    
*LMainLoop
    gosub *LGetEnvarData
    gosub *LRedraw
    
    wait 8
    goto *LMainLoop
    
*LInitialize
    gosub *LSetVariable
    gosub *LSetWindow
    return
    
*LSetVariable
    sdim sData
    sdim sEnvarName
    sdim sResult
    dim  bNoExists, 2
    bChanged = true
    return
    
*LSetWindow
    screen IDW_MAIN, 320, 240, 2
    title "EnvarReader"
    objmode 2
    pos 10, 10 : mes "環境変数の名前を入力してください:"
    pos 30, 30 : input  sEnvarName, 200, 25
    pos 10, 60 : mesbox sResult,    300, 170 : infResult = objinfo(stat, 2), stat
    return
    
*LGetEnvarData
    getenv sData, sEnvarName
    bNoExists(1) = bNoExists(0)
    bNoExists(0) = ( sData == "" )
    
    if ( bNoExists(0) != bNoExists(1) ) {
        bChanged = true
        
        if ( bNoExists(0) ) {
            sResult = "( なし )"
        } else {
            sResult = sData
        }
    }
    
    return
    
*LRedraw
    if ( bChanged == false ) { return }
    
    objenable infResult(1), bNoExists(0) == false
    objprm    infResult(1), sResult
    
    bChanged = false
    return
VBScript版です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Set wshell = CreateObject("WScript.Shell")
Set env = wshell.Environment("SYSTEM")

' PATH環境変数を表示
WScript.Echo("PATH環境変数の値:" & env("PATH"))

' 全ての環境変数を表示
For Each e In env
    WScript.Echo(e)
Next

Index

Feed

Other

Link

Pathtraq

loading...