ProcessBuilder 运行 可以 bash 函数吗?

Can ProcessBuilder run a bash function?

安装 sdkman 后,将以下两行添加到我的 ~/.bashrc:

export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"

并重新加载环境,名为 sdk 的函数在环境中变得可用:

$ type sdk
sdk is a function
sdk () 
{ 
    COMMAND="";
    QUALIFIER="";
    case "$COMMAND" in 
        l)
            COMMAND="list"
        ;;
        ls)
            COMMAND="list"
        ;;
        v)
            COMMAND="version"
        ;;
        u)
            COMMAND="use"
        ;;
        i)
            COMMAND="install"
        ;;
        rm)
            COMMAND="uninstall"
        ;;
        c)
            COMMAND="current"
        ;;
        ug)
            COMMAND="upgrade"
        ;;
        d)
            COMMAND="default"
        ;;
        b)
            COMMAND="broadcast"
        ;;
        h)
            COMMAND="home"
        ;;
        e)
            COMMAND="env"
        ;;
    esac;
    if [[ "$COMMAND" == "home" ]]; then
        __sdk_home "$QUALIFIER" "";
        return $?;
    fi;
    if [[ "$COMMAND" == "completion" ]]; then
        return 0;
    fi;
    if [[ "$COMMAND" != "update" ]]; then
        ___sdkman_check_candidates_cache "$SDKMAN_CANDIDATES_CACHE" || return 1;
    fi;
    ___sdkman_check_version_cache;
    SDKMAN_AVAILABLE="true";
    if [ -z "$SDKMAN_OFFLINE_MODE" ]; then
        SDKMAN_OFFLINE_MODE="false";
    fi;
    __sdkman_update_broadcast_and_service_availability;
    if [ -f "${SDKMAN_DIR}/etc/config" ]; then
        source "${SDKMAN_DIR}/etc/config";
    fi;
    if [[ -z "$COMMAND" ]]; then
        __sdk_help;
        return 1;
    fi;
    CMD_FOUND="";
    CMD_TARGET="${SDKMAN_DIR}/src/sdkman-${COMMAND}.sh";
    if [[ -f "$CMD_TARGET" ]]; then
        CMD_FOUND="$CMD_TARGET";
    fi;
    CMD_TARGET="${SDKMAN_DIR}/ext/sdkman-${COMMAND}.sh";
    if [[ -f "$CMD_TARGET" ]]; then
        CMD_FOUND="$CMD_TARGET";
    fi;
    if [[ -z "$CMD_FOUND" ]]; then
        echo "";
        __sdkman_echo_red "Invalid command: $COMMAND";
        echo "";
        __sdk_help;
    fi;
    local sdkman_valid_candidate=$(echo ${SDKMAN_CANDIDATES[@]} | grep -w "$QUALIFIER");
    if [[ -n "$QUALIFIER" && "$COMMAND" != "help" && "$COMMAND" != "offline" && "$COMMAND" != "flush" && "$COMMAND" != "selfupdate" && "$COMMAND" != "env" && "$COMMAND" != "completion" && "$COMMAND" != "edit" && -z "$sdkman_valid_candidate" ]]; then
        echo "";
        __sdkman_echo_red "Stop! $QUALIFIER is not a valid candidate.";
        return 1;
    fi;
    if [[ "$COMMAND" == "offline" && -n "$QUALIFIER" && -z $(echo "enable disable" | grep -w "$QUALIFIER") ]]; then
        echo "";
        __sdkman_echo_red "Stop! $QUALIFIER is not a valid offline mode.";
    fi;
    local final_rc=0;
    local native_command="${SDKMAN_DIR}/libexec/${COMMAND}";
    local converted_command_name=$(echo "$COMMAND" | tr '-' '_');
    if [ -f "$native_command" ]; then
        if [ -z "$QUALIFIER" ]; then
            "$native_command";
        else
            if [ -z "" ]; then
                "$native_command" "$QUALIFIER";
            else
                if [ -z "" ]; then
                    "$native_command" "$QUALIFIER" "";
                else
                    "$native_command" "$QUALIFIER" "" "";
                fi;
            fi;
        fi;
        final_rc=$?;
    else
        if [ -n "$CMD_FOUND" ]; then
            __sdk_"$converted_command_name" "$QUALIFIER" "" "";
            final_rc=$?;
        fi;
    fi;
    if [[ "$COMMAND" != "selfupdate" && "$sdkman_selfupdate_enable" == true ]]; then
        __sdkman_auto_update "$SDKMAN_REMOTE_VERSION" "$SDKMAN_VERSION";
    fi;
    return $final_rc
}

您可以像 shell 中的普通命令一样使用它。例如:

$ sdk install java 17.0.2-tem

有没有办法使用 ProcessBuilder/Process 从 Java 内部 运行 sdk

除非我创建这样的脚本并从 Java:

调用它
#!/bin/bash

set -e

export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"


sdk install java 17.0.2-tem

我无法通过 ProcessBuilder 运行 sdk 命令:

final var processBuilder = ...;
processBuilder.command("sdk", "install", "java", "17.0.2-tem")
// or
processBuilder.command("/bin/bash", "-c", "sdk", "install", "java", "17.0.2-tem")

是否有任何其他替代方法允许从 Java 调用父环境中定义的函数?

Are there any other alternatives that would allow calling the functions defined in the parent environment from Java?

是的,但是您必须先 source .bashrc 文件。

BufferedReader in = null;
OutputStreamWriter out = null;
try {
  ProcessBuilder pb = new ProcessBuilder("/bin/bash").redirectErrorStream(true);
  Process p = pb.start();
  in = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));
  out = new OutputStreamWriter(p.getOutputStream(), StandardCharsets.UTF_8);
  out.write("source ~/.bashrc\n");
  out.write("sdkman\n");
  out.write("exit\n");
  out.flush();
  String str;
  while((str = in.readLine()) != null) {
        System.out.println(str);
  }
  int response = p.waitFor();
  System.out.println("response: " + response);
  } catch(IOException e) {
      e.printStackTrace();
  } catch(InterruptedException e) {
      e.printStackTrace();
  } finally {
      try { in.close(); } catch(Exception e) {}
      try { out.close(); } catch(Exception e) {}
  }
}