如何使用Java将bash脚本分解为最小的工作块

时间:2011-03-29 05:46:18

标签: java regex bash

我想编写一个Java方法,将一个bash脚本读入一个String对象,然后将该String拆分为最小的String命令数组,这样我就可以一次执行一个命令。我遇到的问题是我需要保持块语句(例如if和while以及输入重定向)完整,即不要进一步分解它们。

例如,以下bash脚本:

./configure --sbindir=/lib/security \
            --docdir=/usr/share/doc/Linux-PAM-1.1.3 \
            --enable-read-both-confs &&

make

install -v -m755 -d /etc/pam.d &&

cat > /etc/pam.d/other << "EOF"
auth     required       pam_deny.so
account  required       pam_deny.so
password required       pam_deny.so
session  required       pam_deny.so
EOF

rm -rfv /etc/pam.d

make install &&
chmod -v 4755 /lib/security/unix_chkpwd &&
mv -v /lib/security/pam_tally /sbin &&
mv -v /lib/libpam{,c,_misc}.la /usr/lib &&
sed -i 's| /lib| /usr/lib|' /usr/lib/libpam_misc.la &&
if [ -L /lib/libpam.so ]; then
   for LINK in libpam{,c,_misc}.so; do
       ln -v -sf ../../lib/$(readlink /lib/${LINK}) /usr/lib/${LINK} &&
       rm -v /lib/${LINK}
   done
fi

echo done

我想以编程方式将其分解为


./configure --sbindir=/lib/security --docdir=/usr/share/doc/Linux-PAM-1.1.3 --enable-read-both-confs

make

install -v -m755 -d /etc/pam.d

cat > /etc/pam.d/other << "EOF"
auth     required       pam_deny.so
account  required       pam_deny.so
password required       pam_deny.so
session  required       pam_deny.so
EOF

rm -rfv /etc/pam.d

make install

chmod -v 4755 /lib/security/unix_chkpwd

mv -v /lib/security/pam_tally /sbin

mv -v /lib/libpam{,c,_misc}.la /usr/lib

sed -i 's| /lib| /usr/lib|' /usr/lib/libpam_misc.la

if [ -L /lib/libpam.so ]
 then
   for LINK in libpam{,c,_misc}.so; do
       ln -v -sf ../../lib/$(readlink /lib/${LINK}) /usr/lib/${LINK} &&
       rm -v /lib/${LINK}
   done
fi

echo done

可以使用正则表达式或使用Java的其他方法吗?

即使是一些伪代码也是受欢迎的。

3 个答案:

答案 0 :(得分:1)

正则表达式对此不够,您需要正确解析语法以获得可靠运行的东西。

解析shell脚本并不容易(没有正式的语法AFAIK)。

一旦你完成解析,执行“逐块”通常不起作用。您需要跟踪环境变量更改,当前目录更改等...

话虽如此,您是否看过像jbash这样的内容?

答案 1 :(得分:0)

你真的需要一个解析器!

看看这个项目jbash,听起来与你想要做的非常相似。

他们似乎已经构建了您需要的所有基本组件!

答案 2 :(得分:0)

这是我到目前为止所得到的。我没有详尽地测试它。

String compoundCommand = null;
ArrayList<String> commandList = new ArrayList<String>();
String list = "";
int count = 0;

ArrayList<String> splitBashScript(String script) {
    script = script.replaceAll("\\\\\n", "");
    script = script.replaceAll("([^;]);([^;])", "$1\n$2");
    String[] lines = Pattern.compile("[ \t]*\n", Pattern.MULTILINE).split(script);
    String delimiter = null;
    for (String line : lines) {
        if (!line.isEmpty()) {
            if (compoundCommand == null) {
                if (line.matches(".*<<.*")) {
                    compoundCommand = "here";
                    delimiter = line.replaceFirst(".*<< *", "").replaceAll("\"", "");
                    list += line;
                } else if (line.matches("[ \t]*for[ \t]*.*")) {
                    compoundCommand = "for";
                    count++;
                    list += line;
                } else if (line.matches("[ \t]*select[ \t]*.*")) {
                    compoundCommand = "select";
                    count++;
                    list += line;
                } else if (line.matches("[ \t]*case[ \t]*.*")) {
                    compoundCommand = "case";
                    count++;
                    list += line;
                } else if (line.matches("[ \t]*if[ \t]*.*")) {
                    compoundCommand = "if";
                    count++;
                    list += line;
                } else if (line.matches("[ \t]*while[ \t]*.*")) {
                    compoundCommand = "while";
                    count++;
                    list += line;
                } else if (line.matches("[ \t]*until[ \t]*.*")) {
                    compoundCommand = "until";
                    count++;
                    list += line;
                } else if (list.isEmpty()) {
                    commandList.add(line.replaceFirst("[ \t]*&&$", ""));
                }
            } else if (compoundCommand.equals("here")) {
                list += "\n" + line;
                if (line.matches(delimiter)) {
                    compoundCommand = null;
                    commandList.add(list.replaceFirst("[ \t]*&&$", ""));
                    list = "";
                }
            } else if (compoundCommand.equals("for")) {
                compound(line, "(for|select|while|until)", "done");
            } else if (compoundCommand.equals("select")) {
                compound(line, "(for|select|while|until)", "done");
            } else if (compoundCommand.equals("case")) {
                compound(line, "case", "esac");
            } else if (compoundCommand.equals("if")) {
                compound(line, "if", "fi");
            } else if (compoundCommand.equals("while")) {
                compound(line, "(for|select|while|until)", "done");
            } else if (compoundCommand.equals("until")) {
                compound(line, "(for|select|while|until)", "done");
            }
        }
    }
    return commandList;
}

void compound(String line, String start, String end) {
    list += "\n" + line;
    if (line.matches("[ \t]*" + start + "[ \t]*.*")) {
        count++;
    }
    if (line.matches("[ \t]*" + end + "[ \t]*.*")) {
        count--;
    }
    if (count == 0) {
        compoundCommand = null;
        commandList.add(list.replaceFirst("[ \t]*&&$", ""));
        list = "";
    }
}