Linux - 通过 shell 脚本运行 jar 文件时的 IO 异常

Posted

技术标签:

【中文标题】Linux - 通过 shell 脚本运行 jar 文件时的 IO 异常【英文标题】:Linux - IO exceptions when running jar file through shell script 【发布时间】:2017-01-02 16:59:43 【问题描述】:

我正在使用 Debain 8.0 - jessie(64 位)。

当我尝试通过 shell 脚本从其目录外部运行 jar 文件时,我遇到了 IO 异常。

目录:“/home/rscedit”

文件:“数据(目录)”“run.sh(文件)”“Webserver.jar(文件)”

当我尝试从“/home/rscedit”以外的任何地方运行“run.sh”时,我的 jar 文件中遇到 IO 异常。

但如果我尝试从“/home/rscedit”运行“run.sh”,它运行得非常好。

我想在启动时运行我的 shell 脚本,所以我应该能够从“/home/rscedit”外部运行我的 shell 脚本,对吧?

Shell 脚本

#!/bin/sh
java -jar -Xmx20480m /home/rscedit/Webserver.jar
read –n1

执行 shell 脚本时遇到的错误

java.nio.file.NoSuchFileException: ./data/log/ipn.log.lck
        at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
        at sun.nio.fs.UnixFileSystemProvider.newFileChannel(UnixFileSystemProvider.java:177)
        at java.nio.channels.FileChannel.open(FileChannel.java:287)
        at java.nio.channels.FileChannel.open(FileChannel.java:335)
        at java.util.logging.FileHandler.openFiles(FileHandler.java:459)
        at java.util.logging.FileHandler.<init>(FileHandler.java:326)
        at org.displee.utilities.logging.LogFactory.loadFileLogger(LogFactory.java:44)
        at org.displee.utilities.logging.LogFactory.<clinit>(LogFactory.java:19)

LogFactory.java

package org.displee.utilities.logging;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.*;

public class LogFactory 

    private static final String FORMAT = "%1$td-%1$tm-%1$tY %1$tH:%1$tM:%1$tS %4$s %2$s - %5$s%6$s%n";

    private static final Map<String, Logger> MAP = new HashMap<>();

    static 
        try 
            loadFileLogger("ipn", "./data/log/ipn.log");
            loadFileLogger("error", "./data/log/error.log");

            Logger logger = Logger.getLogger("console");
            logger.setUseParentHandlers(false);
            ConsoleHandler ch = new ConsoleHandler();
            ch.setFormatter(new ConsoleFormatter());
            ch.setLevel(Level.ALL);
            logger.addHandler(ch);
            register(logger.getName(), logger);
         catch (IOException e) 
            e.printStackTrace();
        
    

    public static void register(String name, Logger logger) 
        MAP.putIfAbsent(name, logger);
    

    public static Logger get(String name) 
        return MAP.get(name);
    

    private static Logger loadFileLogger(String name, String path) throws IOException 
        Logger logger = Logger.getLogger(name);
        FileHandler fh = new FileHandler(path, true);
        fh.setFormatter(new ConsoleFormatter());
        logger.addHandler(fh);
        logger.setUseParentHandlers(false);
        register(name, logger);
        return logger;
    

    private static class ConsoleFormatter extends Formatter 
        @Override
        public synchronized String format(LogRecord record) 
            Date date = new Date();
            date.setTime(record.getMillis());
            String source;
            if (record.getSourceClassName() != null) 
                source = record.getSourceClassName();
                if (record.getSourceMethodName() != null) 
                    source += " " + record.getSourceMethodName();
                
             else 
                source = record.getLoggerName();
            
            String message = formatMessage(record);
            String throwable = "";
            if (record.getThrown() != null) 
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                pw.println();
                record.getThrown().printStackTrace(pw);
                pw.close();
                throwable = sw.toString();
            
            return String.format(FORMAT,
                    date,
                    source,
                    record.getLoggerName(),
                    "LOG",
                    message,
                    throwable);
        
    


我用来执行我的 shell 脚本的命令

exec /home/rscedit/run.sh

编辑:我的数据地图不仅包含日志文件,还包含网站文件等其他内容。

【问题讨论】:

【参考方案1】:

您的 java 程序似乎对工作目录很敏感。我知道的最简单的解决方案,改变这个

java -jar -Xmx20480m /home/rscedit/Webserver.jar

(cd /home/rscedit ; java -jar -Xmx20480m Webserver.jar)

或者,改变Java,这个(以及任何你有模式的地方)

loadFileLogger("ipn", "./data/log/ipn.log");
loadFileLogger("error", "./data/log/error.log");

类似于(使其相对于$HOME),

loadFileLogger("ipn", new File(System.getProperty("user.home"), 
        "data/log/ipn.log").getPath());
loadFileLogger("error", new File(System.getProperty("user.home"), 
        "data/log/error.log").getPath());

【讨论】:

当 linux 尝试在后台运行我的 shell 脚本时,这是否也有效? @Displee 是的。但我添加了另一个选项;这是使您的路径相对于user.home(而不是硬编码相对路径)。 我建议像真正的日志框架那样做——为这些文件路径和日志定义有一个单独的配置文件。或者如果这太多了,只需登录到 stdout/stderr 并在启动时重定向它们。 是的,我也试过了,但是你还需要在数据映射中找到日志配置文件,结果同样的问题。我的数据地图包含更多内容,例如网站文件,而不仅仅是日志文件。

以上是关于Linux - 通过 shell 脚本运行 jar 文件时的 IO 异常的主要内容,如果未能解决你的问题,请参考以下文章

linux 运行和停止jar的shell 脚本

项目jar包上传到shell后怎么用脚本运行

linux crontab 自动运行shell脚本调用jar,crontab是执行了,但是shell没有调用jar是怎么回事?

linux shell调用java的jar包怎么写?

mac下如何用脚本启动jar包程序

Java在linux上调用shell脚本