Как разбить скрипт bash на минимальные рабочие фрагменты, используя Java - PullRequest
0 голосов
/ 29 марта 2011

Я хочу написать метод Java, который читает сценарий bash в один объект 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 ]

1 голос
/ 29 марта 2011

Регулярных выражений недостаточно для этого, вам нужно правильно проанализировать синтаксис, чтобы получить что-то, что работает надежно.

Парсинг сценариев оболочки совсем не прост (без формальной грамматики AFAIK).

И как только вы закончите разбор, выполнение «блок за блоком», как правило, не будет работать. Вам нужно будет отслеживать изменения переменных среды, изменения текущей директории и т. Д. *

Как говорится, вы смотрели на такие вещи как jbash ?

0 голосов
/ 31 марта 2011

Это то, что я получил до сих пор. Я не проверял это полностью.

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 = "";
    }
}
0 голосов
/ 29 марта 2011

Тебе действительно нужен парсер!

Взгляните на этот проект jbash , который звучит очень похоже на то, что вы хотите сделать.

Кажется, они собрали все основные компоненты, которые вам понадобятся!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...