문제

Java에서 환경 변수를 어떻게 설정합니까? 나는 서브 프로세서를 사용하여 이것을 할 수 있다는 것을 알았다. ProcessBuilder. 그러나 몇 가지 하위 프로세스가 시작될 수 있으므로 현재 프로세스의 환경을 수정하고 하위 프로세스가 상속 받도록하겠습니다.

거기에 System.getenv(String) 단일 환경 변수를 얻는 데. 나는 또한 얻을 수 있습니다 Map 완전한 환경 변수 세트 System.getenv(). 그러나 전화 put() 그것에 Map 던졌습니다 UnsupportedOperationException - 분명히 그들은 환경을 읽는다는 것을 의미합니다. 그리고 아무도 없습니다 System.setenv().

그렇다면 현재 실행중인 프로세스에서 환경 변수를 설정하는 방법이 있습니까? 그렇다면 어떻게? 그렇지 않다면 근거는 무엇입니까? (이것은 Java이기 때문에 환경을 만지는 것과 같은 악의적 인 불가능한 일을하지 않아야합니까?) 그리고 그렇지 않다면, 환경 변수를 관리하기위한 좋은 제안은 여러 가지에 먹이를 주어야합니다. 하위 프로세스?

도움이 되었습니까?

해결책

(이것은 Java이기 때문에 환경을 만지는 것과 같은 악의적이지 않은 쓸모없는 일을하지 않아야합니까?)

나는 당신이 머리에 못을 박았다고 생각합니다.

부담을 완화하는 가능한 방법은 방법을 고려하는 것입니다.

void setUpEnvironment(ProcessBuilder builder) {
    Map<String, String> env = builder.environment();
    // blah blah
}

그리고 어떤 통과 ProcessBuilder그들을 시작하기 전에 그것을 통해.

또한 이미 이것을 알고 있지만 동일하게 둘 이상의 프로세스를 시작할 수 있습니다. ProcessBuilder. 따라서 하위 프로세스가 동일하다면이 설정을 반복해서 수행 할 필요가 없습니다.

다른 팁

단위 테스트의 특정 환경 값을 설정 해야하는 시나리오에서 사용하려면 다음 해킹이 유용 할 수 있습니다. JVM 전체의 환경 변수가 변경되므로 테스트 후 변경 사항을 재설정하십시오). 그러나 시스템 환경을 변경하지는 않습니다.

Edward Campbell의 두 Dirty Hacks와 Anonymous의 조합이 가장 잘 작동한다는 것을 알았습니다. Linux에서 작동하지 않으므로 Windows 7에서는 작동하지 않기 때문에 Multiplatform Evil Hack을 얻으려면 다음을 결합했습니다.

protected static void setEnv(Map<String, String> newenv) throws Exception {
  try {
    Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
    Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
    theEnvironmentField.setAccessible(true);
    Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
    env.putAll(newenv);
    Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
    theCaseInsensitiveEnvironmentField.setAccessible(true);
    Map<String, String> cienv = (Map<String, String>)     theCaseInsensitiveEnvironmentField.get(null);
    cienv.putAll(newenv);
  } catch (NoSuchFieldException e) {
    Class[] classes = Collections.class.getDeclaredClasses();
    Map<String, String> env = System.getenv();
    for(Class cl : classes) {
      if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Object obj = field.get(env);
        Map<String, String> map = (Map<String, String>) obj;
        map.clear();
        map.putAll(newenv);
      }
    }
  }
}

이것은 매력처럼 작동합니다. 이 해킹의 두 저자에게 전체 크레딧.

public static void set(Map<String, String> newenv) throws Exception {
    Class[] classes = Collections.class.getDeclaredClasses();
    Map<String, String> env = System.getenv();
    for(Class cl : classes) {
        if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
            Field field = cl.getDeclaredField("m");
            field.setAccessible(true);
            Object obj = field.get(env);
            Map<String, String> map = (Map<String, String>) obj;
            map.clear();
            map.putAll(newenv);
        }
    }
}

또는 단일 VAR을 추가/업데이트하고 TheJoshWolfe의 제안에 따라 루프를 제거합니다.

@SuppressWarnings({ "unchecked" })
  public static void updateEnv(String name, String val) throws ReflectiveOperationException {
    Map<String, String> env = System.getenv();
    Field field = env.getClass().getDeclaredField("m");
    field.setAccessible(true);
    ((Map<String, String>) field.get(env)).put(name, val);
  }
// this is a dirty hack - but should be ok for a unittest.
private void setNewEnvironmentHack(Map<String, String> newenv) throws Exception
{
  Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
  Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
  theEnvironmentField.setAccessible(true);
  Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
  env.clear();
  env.putAll(newenv);
  Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
  theCaseInsensitiveEnvironmentField.setAccessible(true);
  Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
  cienv.clear();
  cienv.putAll(newenv);
}

안드로이드에서 인터페이스는 libcore.os를 통해 일종의 숨겨진 API로 노출됩니다.

Libcore.os.setenv("VAR", "value", bOverwrite);
Libcore.os.getenv("VAR"));

인터페이스 OS뿐만 아니라 Libcore 클래스는 공개적입니다. 클래스 선언 만 누락되었으며 링커에 표시되어야합니다. 클래스를 응용 프로그램에 추가 할 필요는 없지만 포함 된 경우에도 아프지 않습니다.

package libcore.io;

public final class Libcore {
    private Libcore() { }

    public static Os os;
}

package libcore.io;

public interface Os {
    public String getenv(String name);
    public void setenv(String name, String value, boolean overwrite) throws ErrnoException;
}

리눅스 만

단일 환경 변수 설정 (Edward Campbell의 답변 기반) :

public static void setEnv(String key, String value) {
    try {
        Map<String, String> env = System.getenv();
        Class<?> cl = env.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String, String> writableEnv = (Map<String, String>) field.get(env);
        writableEnv.put(key, value);
    } catch (Exception e) {
        throw new IllegalStateException("Failed to set environment variable", e);
    }
}

용법:

먼저, 메소드를 원하는 클래스 (예 : SystemUtil)에 넣으십시오.

SystemUtil.setEnv("SHELL", "/bin/bash");

전화하면 System.getenv("SHELL") 그 후, 당신은 얻을 수 있습니다 "/bin/bash" 뒤.

Android는 실제로 Java가 아니기 때문에@Pushy/@Anonymous/@Edward Campbell의 솔루션이 Android에서 작동하지 않습니다. 구체적으로, Android는 가지고 있지 않습니다 java.lang.ProcessEnvironment 조금도. 그러나 Android에서는 더 쉬운 것으로 판명됩니다. Posix에 JNI 호출을해야합니다. setenv():

C/JNI에서 :

JNIEXPORT jint JNICALL Java_com_example_posixtest_Posix_setenv
  (JNIEnv* env, jclass clazz, jstring key, jstring value, jboolean overwrite)
{
    char* k = (char *) (*env)->GetStringUTFChars(env, key, NULL);
    char* v = (char *) (*env)->GetStringUTFChars(env, value, NULL);
    int err = setenv(k, v, overwrite);
    (*env)->ReleaseStringUTFChars(env, key, k);
    (*env)->ReleaseStringUTFChars(env, value, v);
    return err;
}

그리고 자바에서 :

public class Posix {

    public static native int setenv(String key, String value, boolean overwrite);

    private void runTest() {
        Posix.setenv("LD_LIBRARY_PATH", "foo", true);
    }
}

이것은 Paul Blair가 지적한 일부 정리와 @Pushy의 코드 내부에있는 @Edward Campbell과 익명으로 구성된 실수를 포함하여 Java로 변환 된 @Paul-Blair의 답변의 조합입니다.

이 코드가 테스트에서만 사용되어야하는 양을 강조 할 수 없으며 매우 해킹됩니다. 그러나 테스트에서 환경 설정이 필요한 경우 정확히 필요한 것입니다.

여기에는 또한 코드가 실행중인 두 창에서 코드가 작동 할 수있는 약간의 광산 터치도 포함됩니다.

java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

Centos뿐만 아니라 실행 중입니다

openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

구현 :

/**
 * Sets an environment variable FOR THE CURRENT RUN OF THE JVM
 * Does not actually modify the system's environment variables,
 *  but rather only the copy of the variables that java has taken,
 *  and hence should only be used for testing purposes!
 * @param key The Name of the variable to set
 * @param value The value of the variable to set
 */
@SuppressWarnings("unchecked")
public static <K,V> void setenv(final String key, final String value) {
    try {
        /// we obtain the actual environment
        final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
        final boolean environmentAccessibility = theEnvironmentField.isAccessible();
        theEnvironmentField.setAccessible(true);

        final Map<K,V> env = (Map<K, V>) theEnvironmentField.get(null);

        if (SystemUtils.IS_OS_WINDOWS) {
            // This is all that is needed on windows running java jdk 1.8.0_92
            if (value == null) {
                env.remove(key);
            } else {
                env.put((K) key, (V) value);
            }
        } else {
            // This is triggered to work on openjdk 1.8.0_91
            // The ProcessEnvironment$Variable is the key of the map
            final Class<K> variableClass = (Class<K>) Class.forName("java.lang.ProcessEnvironment$Variable");
            final Method convertToVariable = variableClass.getMethod("valueOf", String.class);
            final boolean conversionVariableAccessibility = convertToVariable.isAccessible();
            convertToVariable.setAccessible(true);

            // The ProcessEnvironment$Value is the value fo the map
            final Class<V> valueClass = (Class<V>) Class.forName("java.lang.ProcessEnvironment$Value");
            final Method convertToValue = valueClass.getMethod("valueOf", String.class);
            final boolean conversionValueAccessibility = convertToValue.isAccessible();
            convertToValue.setAccessible(true);

            if (value == null) {
                env.remove(convertToVariable.invoke(null, key));
            } else {
                // we place the new value inside the map after conversion so as to
                // avoid class cast exceptions when rerunning this code
                env.put((K) convertToVariable.invoke(null, key), (V) convertToValue.invoke(null, value));

                // reset accessibility to what they were
                convertToValue.setAccessible(conversionValueAccessibility);
                convertToVariable.setAccessible(conversionVariableAccessibility);
            }
        }
        // reset environment accessibility
        theEnvironmentField.setAccessible(environmentAccessibility);

        // we apply the same to the case insensitive environment
        final Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
        final boolean insensitiveAccessibility = theCaseInsensitiveEnvironmentField.isAccessible();
        theCaseInsensitiveEnvironmentField.setAccessible(true);
        // Not entirely sure if this needs to be casted to ProcessEnvironment$Variable and $Value as well
        final Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
        if (value == null) {
            // remove if null
            cienv.remove(key);
        } else {
            cienv.put(key, value);
        }
        theCaseInsensitiveEnvironmentField.setAccessible(insensitiveAccessibility);
    } catch (final ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">", e);
    } catch (final NoSuchFieldException e) {
        // we could not find theEnvironment
        final Map<String, String> env = System.getenv();
        Stream.of(Collections.class.getDeclaredClasses())
                // obtain the declared classes of type $UnmodifiableMap
                .filter(c1 -> "java.util.Collections$UnmodifiableMap".equals(c1.getName()))
                .map(c1 -> {
                    try {
                        return c1.getDeclaredField("m");
                    } catch (final NoSuchFieldException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+"> when locating in-class memory map of environment", e1);
                    }
                })
                .forEach(field -> {
                    try {
                        final boolean fieldAccessibility = field.isAccessible();
                        field.setAccessible(true);
                        // we obtain the environment
                        final Map<String, String> map = (Map<String, String>) field.get(env);
                        if (value == null) {
                            // remove if null
                            map.remove(key);
                        } else {
                            map.put(key, value);
                        }
                        // reset accessibility
                        field.setAccessible(fieldAccessibility);
                    } catch (final ConcurrentModificationException e1) {
                        // This may happen if we keep backups of the environment before calling this method
                        // as the map that we kept as a backup may be picked up inside this block.
                        // So we simply skip this attempt and continue adjusting the other maps
                        // To avoid this one should always keep individual keys/value backups not the entire map
                        LOGGER.info("Attempted to modify source map: "+field.getDeclaringClass()+"#"+field.getName(), e1);
                    } catch (final IllegalAccessException e1) {
                        throw new IllegalStateException("Failed setting environment variable <"+key+"> to <"+value+">. Unable to access field!", e1);
                    }
                });
    }
    LOGGER.info("Set environment variable <"+key+"> to <"+value+">. Sanity Check: "+System.getenv(key));
}

온라인 주위를 찌르면 JNI와 함께 할 수있을 것 같습니다. 그런 다음 C에서 putenv ()에게 전화를해야하며, 아마도 Windows와 Unix에서 작동하는 방식으로 (아마도) 그것을해야 할 것입니다.

모든 일을 할 수 있다면, Java 자체가 나를 직선 재킷에 넣는 대신 이것을 지원하기가 어렵지 않을 것입니다.

다른 곳의 Perl을 사용하는 친구는 이것이 환경 변수가 프로세스 전 세계이며 Java가 좋은 디자인을 위해 좋은 격리를 위해 노력하고 있기 때문이라고 제안합니다.

위의 Pushy의 대답을 시도했고 대부분은 효과가있었습니다. 그러나 특정 상황에서는이 예외를 볼 것입니다.

java.lang.String cannot be cast to java.lang.ProcessEnvironment$Variable

이것은 특정 내부 클래스의 구현으로 인해이 방법이 두 번 이상 호출 될 때 발생하는 것으로 나타났습니다. ProcessEnvironment. 만약 setEnv(..) 키가 theEnvironment 지도, 그들은 이제 끈입니다 (첫 번째 호출에 의해 현으로 들어갔다 setEnv(...) ) 그리고지도의 일반적인 유형으로 캐스트 할 수없고 Variable, 개인 내부 클래스입니다 ProcessEnvironment.

고정 된 버전 (Scala)은 다음과 같습니다. 바라건대 Java로 이월하는 것은 그리 어렵지 않습니다.

def setEnv(newenv: java.util.Map[String, String]): Unit = {
  try {
    val processEnvironmentClass = JavaClass.forName("java.lang.ProcessEnvironment")
    val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
    theEnvironmentField.setAccessible(true)

    val variableClass = JavaClass.forName("java.lang.ProcessEnvironment$Variable")
    val convertToVariable = variableClass.getMethod("valueOf", classOf[java.lang.String])
    convertToVariable.setAccessible(true)

    val valueClass = JavaClass.forName("java.lang.ProcessEnvironment$Value")
    val convertToValue = valueClass.getMethod("valueOf", classOf[java.lang.String])
    convertToValue.setAccessible(true)

    val sampleVariable = convertToVariable.invoke(null, "")
    val sampleValue = convertToValue.invoke(null, "")
    val env = theEnvironmentField.get(null).asInstanceOf[java.util.Map[sampleVariable.type, sampleValue.type]]
    newenv.foreach { case (k, v) => {
        val variable = convertToVariable.invoke(null, k).asInstanceOf[sampleVariable.type]
        val value = convertToValue.invoke(null, v).asInstanceOf[sampleValue.type]
        env.put(variable, value)
      }
    }

    val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
    theCaseInsensitiveEnvironmentField.setAccessible(true)
    val cienv = theCaseInsensitiveEnvironmentField.get(null).asInstanceOf[java.util.Map[String, String]]
    cienv.putAll(newenv);
  }
  catch {
    case e : NoSuchFieldException => {
      try {
        val classes = classOf[java.util.Collections].getDeclaredClasses
        val env = System.getenv()
        classes foreach (cl => {
          if("java.util.Collections$UnmodifiableMap" == cl.getName) {
            val field = cl.getDeclaredField("m")
            field.setAccessible(true)
            val map = field.get(env).asInstanceOf[java.util.Map[String, String]]
            // map.clear() // Not sure why this was in the code. It means we need to set all required environment variables.
            map.putAll(newenv)
          }
        })
      } catch {
        case e2: Exception => e2.printStackTrace()
      }
    }
    case e1: Exception => e1.printStackTrace()
  }
}

이 스레드를 찾은 대부분의 사람들과 마찬가지로, 나는 일부 단위 테스트를 작성하고 있었고 테스트가 실행되는 올바른 조건을 설정하기 위해 환경 변수를 수정해야했습니다. 그러나 가장 중요한 답변에는 몇 가지 문제가 있거나 매우 비밀 스럽거나 지나치게 복잡하다는 것을 알았습니다. 바라건대 이것은 다른 사람들이 솔루션을 더 빨리 분류하는 데 도움이되기를 바랍니다.

우선, 나는 마침내 @hubert grzeskowiak의 해결책이 가장 간단한 것을 발견했으며 그것은 저에게 효과적이었습니다. 나는 내가 먼저 그게 왔으면 좋겠다. @edward Campbell의 답변을 기반으로하지만 루프 검색을위한 복잡한 것입니다.

그러나 나는 @pushy의 솔루션으로 시작하여 가장 큰 발전을 얻었습니다. 그것은 @anonymous와 @edward campbell의 콤보입니다. @pushy는 Linux와 Windows 환경을 모두 다루기 위해 두 가지 접근 방식이 모두 필요하다고 주장합니다. 나는 OS X에서 실행 중이며 두 작업을 모두 발견했습니다 (@anonymous 접근 방식의 문제는 고정되어 있습니다). 다른 사람들이 지적 했듯이이 솔루션은 대부분 작동하지만 전부는 아닙니다.

대부분의 혼란의 원천은 'Theenvironment'분야에서 작동하는 @Anonymous의 솔루션에서 비롯된 것 같습니다. 정의를보고 있습니다 프로세스 환경 구조, 'TheEnvironment'는 <문자열, 문자열>이 아니라 오히려 맵 <변수, 값>입니다. 맵을 지우는 것은 잘 작동하지만 putall 조작은 맵을 재구성하여 <string, string> 맵을 재구성합니다. 이는 맵 <변수, value>를 기대하는 일반 API를 사용하여 후속 작업이 데이터 구조에서 작동 할 때 문제를 일으킬 수 있습니다. 또한 개별 요소에 액세스/제거하는 것이 문제입니다. 해결책은 'Theunmodifiable Environment'를 통해 간접적으로 'Theenvironment'에 액세스하는 것입니다. 그러나 이것은 유형이기 때문입니다 Unmodifiablemap 액세스는 unmodifiablemap 유형의 개인 변수 'm'을 통해 수행해야합니다. 아래 코드의 getModifiableEnvironmentMap2를 참조하십시오.

제 경우에는 테스트의 환경 변수 중 일부를 제거해야했습니다 (다른 것들은 변하지 않아야합니다). 그런 다음 테스트 후 환경 변수를 이전 상태로 복원하고 싶었습니다. 아래의 루틴은이를 바로 앞으로 만듭니다. OS X에서 getModifiableenvironmentMap의 두 버전을 테스트했으며 동등하게 작동합니다. 이 스레드의 의견을 기반으로하지만 환경에 따라 다른 것보다 더 나은 선택 일 수 있습니다.

참고 : 'thecaseinsensivelyenvironmentfield'에 대한 액세스는 포함되지 않았습니다. 왜냐하면 Windows 특정 인 것처럼 보이고 테스트 할 방법이 없었지만 추가해야합니다.

private Map<String, String> getModifiableEnvironmentMap() {
    try {
        Map<String,String> unmodifiableEnv = System.getenv();
        Class<?> cl = unmodifiableEnv.getClass();
        Field field = cl.getDeclaredField("m");
        field.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) field.get(unmodifiableEnv);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> getModifiableEnvironmentMap2() {
    try {
        Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
        Field theUnmodifiableEnvironmentField = processEnvironmentClass.getDeclaredField("theUnmodifiableEnvironment");
        theUnmodifiableEnvironmentField.setAccessible(true);
        Map<String,String> theUnmodifiableEnvironment = (Map<String,String>)theUnmodifiableEnvironmentField.get(null);

        Class<?> theUnmodifiableEnvironmentClass = theUnmodifiableEnvironment.getClass();
        Field theModifiableEnvField = theUnmodifiableEnvironmentClass.getDeclaredField("m");
        theModifiableEnvField.setAccessible(true);
        Map<String,String> modifiableEnv = (Map<String,String>) theModifiableEnvField.get(theUnmodifiableEnvironment);
        return modifiableEnv;
    } catch(Exception e) {
        throw new RuntimeException("Unable to access writable environment variable map.");
    }
}

private Map<String, String> clearEnvironmentVars(String[] keys) {

    Map<String,String> modifiableEnv = getModifiableEnvironmentMap();

    HashMap<String, String> savedVals = new HashMap<String, String>();

    for(String k : keys) {
        String val = modifiableEnv.remove(k);
        if (val != null) { savedVals.put(k, val); }
    }
    return savedVals;
}

private void setEnvironmentVars(Map<String, String> varMap) {
    getModifiableEnvironmentMap().putAll(varMap);   
}

@Test
public void myTest() {
    String[] keys = { "key1", "key2", "key3" };
    Map<String, String> savedVars = clearEnvironmentVars(keys);

    // do test

    setEnvironmentVars(savedVars);
}

이것은 @Pushy 's Evil의 Kotlin Evil 버전입니다. 대답 =)

@Suppress("UNCHECKED_CAST")
@Throws(Exception::class)
fun setEnv(newenv: Map<String, String>) {
    try {
        val processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment")
        val theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment")
        theEnvironmentField.isAccessible = true
        val env = theEnvironmentField.get(null) as MutableMap<String, String>
        env.putAll(newenv)
        val theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment")
        theCaseInsensitiveEnvironmentField.isAccessible = true
        val cienv = theCaseInsensitiveEnvironmentField.get(null) as MutableMap<String, String>
        cienv.putAll(newenv)
    } catch (e: NoSuchFieldException) {
        val classes = Collections::class.java.getDeclaredClasses()
        val env = System.getenv()
        for (cl in classes) {
            if ("java.util.Collections\$UnmodifiableMap" == cl.getName()) {
                val field = cl.getDeclaredField("m")
                field.setAccessible(true)
                val obj = field.get(env)
                val map = obj as MutableMap<String, String>
                map.clear()
                map.putAll(newenv)
            }
        }
    }

적어도 Macos Mojave에서 일하고 있습니다.

Kotlin 구현에 Edward의 답변을 바탕으로 한 Kotlin 구현 :

fun setEnv(newEnv: Map<String, String>) {
    val unmodifiableMapClass = Collections.unmodifiableMap<Any, Any>(mapOf()).javaClass
    with(unmodifiableMapClass.getDeclaredField("m")) {
        isAccessible = true
        @Suppress("UNCHECKED_CAST")
        get(System.getenv()) as MutableMap<String, String>
    }.apply {
        clear()
        putAll(newEnv)
    }
}

-D를 사용하여 매개 변수를 초기 Java 프로세스로 전달할 수 있습니다.

java -cp <classpath> -Dkey1=value -Dkey2=value ...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top