Bash: как автоматически вставить пробелы в соответствии с отступом? - PullRequest
0 голосов
/ 22 января 2011

У меня много отладочных операторов, делающих нечитаемые трассировки стека (не мой вызов), например:

 00:53:59,906  - j.util.indexing.FileBasedIndex - START INDEX SHUTDOWN 
 00:53:09,192  - .impl.stores.XmlElementStorage - Document was not loaded for $APP_CONFIG$/macros.xml 
 00:53:09,195  - s.impl.stores.FileBasedStorage - Document was not loaded for $APP_CONFIG$/quicklists.xml file is null 
 00:53:09,195  - .impl.stores.XmlElementStorage - Document was not loaded for $APP_CONFIG$/quicklists.xml 
 00:53:09,696  - ij.openapi.wm.impl.IdeRootPane - App initialization took 5584 ms 
 00:53:11,677  -                  TestNG Runner - Create TestNG Template Configuration 
 00:53:13,628  - indexing.UnindexedFilesUpdater - Unindexed files update started 
 00:53:15,370  - indexing.UnindexedFilesUpdater - Unindexed files update done 
 00:53:20,873  - tor.impl.FileEditorManagerImpl - Project opening took 10569 ms 
 00:53:31,862  - s.impl.stores.FileBasedStorage - Document was not loaded for $APP_CONFIG$/intentionSettings.xml file is null 
 00:53:31,862  - .impl.stores.XmlElementStorage - Document was not loaded for $APP_CONFIG$/intentionSettings.xml 
 00:54:00,723  - j.util.indexing.FileBasedIndex - END INDEX SHUTDOWN

И я хочу, чтобы они выглядели так:

 00:53:59,906  - j.util.indexing.FileBasedIndex - START INDEX SHUTDOWN 
 00:53:09,192  - .impl.stores.XmlElementStorage -   Document was not loaded for $APP_CONFIG$/macros.xml 
 00:53:09,195  - s.impl.stores.FileBasedStorage -   Document was not loaded for $APP_CONFIG$/quicklists.xml file is null 
 00:53:09,195  - .impl.stores.XmlElementStorage -   Document was not loaded for $APP_CONFIG$/quicklists.xml 
 00:53:09,696  - ij.openapi.wm.impl.IdeRootPane -     App initialization took 5584 ms 
 00:53:11,677  -                  TestNG Runner -       Create TestNG Template Configuration 
 00:53:13,628  - indexing.UnindexedFilesUpdater -        Unindexed files update started 
 00:53:15,370  - indexing.UnindexedFilesUpdater -        Unindexed files update done 
 00:53:20,873  - tor.impl.FileEditorManagerImpl -     Project opening took 10569 ms 
 00:53:31,862  - s.impl.stores.FileBasedStorage -    Document was not loaded for $APP_CONFIG$/intentionSettings.xml file is null 
 00:53:31,862  - .impl.stores.XmlElementStorage -   Document was not loaded for $APP_CONFIG$/intentionSettings.xml 
 00:54:00,723  - j.util.indexing.FileBasedIndex - END INDEX SHUTDOWN

Теперь мой код отформатирован автоматически, поэтому я точно знаю, сколько символов в исходном коде для уровня отступа.

Что я хочу сделать, так это автоматически заменять каждую строку в моем коде следующим образом:

log.debug("some silly debug line");

с:

log.debug(" " + "some silly debug line");

или

log.debug("  " + "some silly debug line");

в зависимости от количества отступов перед строкой log.debug.

Я почти уверен, что магия Bash / shell может сделать это автоматически.

В основном я бы начал с:

find . -iname "*java" -exec ...

тогда я бы хотел вставить "" в строки, начинающиеся с log.debug, в зависимости от уровня отступа этих строк.

Как бы я поступил?

EDIT

Черт: он должен быть в состоянии запускаться несколько раз, без смещения строк, уже содержащих log.debug ("" +) . Все становится сложнее, но теперь, благодаря хорошему ответу, у меня есть с чего начать:)

Примечание : прежде чем кричать и стрелять, почему это не очень хорошая идея, прочитайте мой комментарий (ы)

Ответы [ 4 ]

2 голосов
/ 22 января 2011

Это должно работать при многократном запуске файлов:

sed -i.bak 's/^\([[:blank:]]*\)\(log.debug(\)\("[[:blank:]]*" + \)\?/\1\2"\1" + /; s/^log.debug("" + /log.debug(/'

В сочетании с командой поиска:

find . -iname "*java" -exec sed -i.bak 's/^\([[:blank:]]*\)\(log.debug(\)\("[[:blank:]]*" + \)\?/\1\2"\1" + /; s/^log.debug("" + /log.debug(/' \;

Тестовый запуск:

$ sed -i.bak '...' test.java
$ diff test.java test.java.bak
(report of differences)
$ sed -i.bak '...' test.java
$ diff test.java test.java.bak
(no differences)

Объяснениеиз sed команда:

s/^\([[:blank:]]*\)\(log.debug(\)\("[[:blank:]]*" + \)\?/\1\2"\1" + /
  • Захватить табуляцию и пробелы, если таковые имеются, в начале строки в группу \1.
  • Захватить строку «Журнал».debug ("(только для того, чтобы нам не нужно было это повторять дословно) в группу \2.
  • Захватите любую существующую строку отступа ("indentlevel" +) в нее, чтобы ее можно было перезаписать в случае, если отступ имеетизменено. \? делает его существование необязательным. Нам все равно, что это будет группа захвата \3, так как мы ее выбрасываем. Скобки необходимы только для \?.
  • Теперь замена выводится. Группы захвата \1 (отступ) и \2 (log.debug ()) возвращаются, как они были. И добавляется "indentlevel" + (где "indentlevel" - та же последовательностьиз пробельных символов, которые с отступом строки). Обратите внимание, что это может привести к ничему между тон цитирует.

Следующая часть команды удаляет отступы, если они нулевые.Вы можете пропустить это, если не возражаете против результирующих строк вида log.debug("" + "foo"), когда строка не имеет отступа.

s/^log.debug("" + /log.debug(/
2 голосов
/ 22 января 2011

Попробуйте заменить строку sed:

find . -type f -iname "*.java" -exec sed -i 's/\(\(\s\+\)log.debug(\)\(.*)\)/\1"\2" + \3/' {} \;

Давайте подробнее рассмотрим шаблоны регулярных выражений в sed -i 's/\(\(\s\+\)log.debug(\)\(.*)\)/\1"\2" + \3/ ...

Группа 1 является исходным начальным текстом, включая пробелы и "log.debug (" (с открытой круглой скобкой).
\(\(\s\+\)log.debug(\)

Группа 2, которая находится внутри группы 1, показанной выше, захватывает только первые пробелы:
\(\s\+\)

Группа 3 - это оригинальный оставшийся текст после "log.debug (":
\(.*)\)

sed использует эти группы захвата для формирования замещающей строки, которая начинается с исходного начального текста, после исходного начального пробела, окруженного кавычками, затем символа плюс (для объединения строк Java) и, наконец, оставшегося исходного текста: 1019 * \1"\2" + \3

1 голос
/ 22 января 2011

И вы были правы! 1

sed -i .tmp -e 's/^\( *\)log.debug(/\1log.debug("\1" + /' prog.java

Интегрировано с find(1) становится:

find . -name \*.java -a -exec sed -i .tmp -e 's/^\( *\)log.debug(/\1log.debug("\1" + /' {} \;

Это находит все с именем * .java и запускаетсяпрограмма sed (потоковый редактор), находящаяся на месте, сопоставляет изменяемые строки с \ (группа захвата \) вокруг строки пробела, а затем прикрепляет группу захвата обратно туда, где она находилась, а также перед вашей строкой,

-a, -exec, \;и {} - просто тайный синтаксис find для " и ", " выполнение программы ", " завершение выполняемой команды " и " подставьте найденное имя файла здесь".


1.Когда вы сказали: «Я почти уверен, что магия Bash / shell может сделать это автоматически».

1 голос
/ 22 января 2011

Вы можете попробовать этот скрипт на awk:

x.awk

/log.debug/ {
    logStart = match($0, "log");
    spaces = substr($0, 0, logStart);
    gap = "\"" spaces "\"";
    parenStart = match($0, "(");
    firstHalf = substr($0, 0, parenStart);
    lastHalf = substr($0, parenStart, length($0) - parenStart);
    print firstHalf gap " + " lastHalf;
    next;
}
{
    print;
}

awk -f x.awk orig.java> new.java

Простой способсделать это будет:

cd /code/root
mkdir /tmp/newcode
cp -R * /tmp/newcode
for i in `find . -name "*.java"`
do
    awk -f x.awk > /tmp/newcode/$i
done

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

Не проверено, естьможет легко быть единственной ошибкой в ​​разбиении строки, но это должно помочь вам начать.

...