草庐IT

java:自定义变量加载到系统变量后替换shell模版并执行shell

鲲志说 2023-05-01 原文

这里的需求前提是,在项目中进行某些操作前,需要在命令后对shell配置文件的进行修改(如ip、port),这个对于用户是不友好的,需要改为用户页面输入ip、port,后台自动去操作修改配置;那么这篇博客的由来就有了。


上面图片是AI创作,未经允许,不可商用哦!

目录


以下为实际工作简化后描述

实现功能描述

  1. 项目加载自定义变量
  2. 自定义变量替换shell模版内容
  3. 项目运行shell

功能实现拆解

针对上述功能描述,其实可以拆解为三步

  1. 实现项目加载自定义变量
  2. 实现替换shell模版内容
  3. 运行shell

项目加载自定义变量

这里有两种实现,
一种是项目加载自定义变量文件到系统变量中;
另一种是shell通过source .env环境变量方式加载。

项目加载自定义变量文件到系统变量中

这种方法的好处是项目中可以获取到自定义变量,如果项目代码需要获取自定义变量进行操作,可以考虑使用此方式

新增一个自定义变量文件(当然也可以在代码中固定写入变量直接加载到系统中,这样的缺点就是不灵活,如果有变动就需要改代码)

自定义变量文件如下

BASE_ROOT_DIR=/home
LICENSE_PATH=/home/LICENSE
PACKAGE_PATH=/home/test.tar.gz

java代码如下

    /**
     * 加载自定义变量文件到系统变量中
     * @param configFile
     */
    public static void loadProperties(String configFile){
        try {
            FileInputStream propFile = new FileInputStream(configFile);
            Properties p = new Properties(System.getProperties());
            p.load(propFile);
            System.setProperties(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

调用loadProperties方法后,就可以通过System.getProperty("key")获取自定义的变量了
如获取BASE_ROOT_DIRSystem.getProperty("BASE_ROOT_DIR")

实操验证如下

自定义变量文件

测试代码

import java.io.FileInputStream;
import java.util.Properties;

public class LoadProperties {

    public static void main(String[] args) {

        String configFile = "/Users/kunzhi/Downloads/learn/linuxTest/config.sh";
        loadProperties(configFile);
        System.out.println("BASE_ROOT_DIR: " + System.getProperty("BASE_ROOT_DIR"));
        System.out.println("LICENSE_PATH: " + System.getProperty("LICENSE_PATH"));
        System.out.println("PACKAGE_PATH: " + System.getProperty("PACKAGE_PATH"));
    }

    public static void loadProperties(String configFile){
        try {
            FileInputStream propFile = new FileInputStream(configFile);
            Properties p = new Properties(System.getProperties());
            p.load(propFile);
            System.setProperties(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行输出结果

shell通过source .env环境变量文件方式加载

这种方法的好处是在shell执行时直接获取环境变量,不需要项目代码做多余的操作

  1. 新增一个.env环境变量文件(如test.env)
  2. 当在执行的shell文件中首行加入source命令(source test.env)或者先在命令行执行命令source test.env后,执行shell文件

test.env环境变量文件如下

BASE_ROOT_DIR=/home
LICENSE_PATH=/home/LICENSE
PACKAGE_PATH=/home/test.tar.gz

shell模版文件如下

cd ${DATASYS_BASE_ROOT_DIR}
pwd

echo "DATASYS_PACKAGE_PATH: ${DATASYS_PACKAGE_PATH}"
echo "PACKAGE_PATH: ${PACKAGE_PATH}"
echo "LICENSE_PATH: ${LICENSE_PATH}"

实操验证如下

创建shell模版文件 test.sh,并执行

创建环境变量文件 test.env,并在test.sh文件首行加入命令:source test.env

替换shell模版并运行

因为替换是否成功,只有通过运行结果才能有力证明,所以我们放在一起看

由于替换shell模版内容的具体操作受自定义变量加载方式影响,所以我们还是按照两种加载方式来看

项目加载自定义变量文件到系统变量中

如果是项目加载自定义变量文件到系统变量中,还需要项目获取变量并传入shell替换;

代码如下

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Properties;

public class LoadProperties {

    public static void main(String[] args) {

        String configFile = "/Users/kunzhi/Downloads/learn/linuxTest/config.sh";
        //加载自定义环境变量
        loadProperties(configFile);

        String BASE_ROOT_DIR = System.getProperty("BASE_ROOT_DIR");
        String LICENSE_PATH = System.getProperty("LICENSE_PATH");
        String PACKAGE_PATH = System.getProperty("PACKAGE_PATH");
        System.out.println(BASE_ROOT_DIR + ": " + System.getProperty("BASE_ROOT_DIR"));
        System.out.println(LICENSE_PATH + ": " + System.getProperty("LICENSE_PATH"));
        System.out.println(PACKAGE_PATH + ": " + System.getProperty("PACKAGE_PATH"));
        
        //需要传入shell模版替换的内容
        String[] evnp = {"BASE_ROOT_DIR=" + BASE_ROOT_DIR, "LICENSE_PATH=" + LICENSE_PATH, "PACKAGE_PATH=" + PACKAGE_PATH};
        String shellFile = "/Users/kunzhi/Downloads/learn/linuxTest/test1.sh";
        //替换并运行shell
        replaceAndRun(shellFile, evnp);
    }

    //加载自定义环境变量
    public static void loadProperties(String configFile){
        try {
            FileInputStream propFile = new FileInputStream(configFile);
            Properties p = new Properties(System.getProperties());
            p.load(propFile);
            System.setProperties(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //替换并运行shell
    private static void replaceAndRun(String path, String[] evnp) {
        try {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", path}, evnp,null);
            //只有process.waitFor() 结果为0,才说明执行成功了
            if (process.waitFor() != 0) {
                throw new Exception(String.valueOf(process.waitFor()));
            }

            InputStreamReader ir = new InputStreamReader(process.getInputStream());
            LineNumberReader input = new LineNumberReader(ir);
            String line;
            //输入shell中执行的每一行
            while ((line = input.readLine()) != null){
                if (line.contains("ERROR")) {
                    throw new Exception("ERROR");
                }
                System.out.println(line);
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

运行结果

shell通过source .env环境变量文件方式加载

如果是shell通过source .env环境变量方式加载,在上一步实操演示可以看出,其实已经达到替换效果,直接执行shell文件即可了

代码如下

package test;

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Properties;

/**
 * @author yanZhiHang
 * @date 2023/2/26 17:06
 */
public class LoadProperties {

    public static void main(String[] args) {
        runShell(shellFile1);
    }

    private static void runShell(String path) {
        try {
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", path}, null,null);

            if (process.waitFor() != 0) {
                throw new Exception(String.valueOf(process.waitFor()));
            }

            InputStreamReader ir = new InputStreamReader(process.getInputStream());
            LineNumberReader input = new LineNumberReader(ir);
            String line;
            while ((line = input.readLine()) != null){
                if (line.contains("ERROR")) {
                    throw new Exception("ERROR");
                }
                System.out.println(line);
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

有关java:自定义变量加载到系统变量后替换shell模版并执行shell的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  3. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  8. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  9. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  10. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

随机推荐