Ладно, похоже, я не могу найти способ сделать то, что мне нужно.
Допустим, у меня есть текстовый файл A, например такой:
(freqBiasL2[27])
(SatBiasL1[27])
(defSatBiasL2_L1[27])
(defSatBiasSlope[27])
(defSatBiasSigma[27])
(freqBiasL2[28])
(SatBiasL1[28])
(defSatBiasL2_L1[28])
(defSatBiasSlope[28])
(defSatBiasSigma[28])
(freqBiasL2[29])
(SatBiasL1[29])
(defSatBiasL2_L1[29])
(defSatBiasSlope[29])
(defSatBiasSigma[29])
и т. д. Я хочу изменить индекс между скобками [] так, чтобы каждый индекс i был = i+3.
Я пробовал использовать комбинацию цикла for и sed, но не работает
for i in {27..107..1}
do
i_new=$((i+3))
sed -e 's/\['$i'\]/\['$i_new'\]/' prova.txt
done
Проблема в том, что он изменит первые 27 на 30, но при следующих интерпретациях найдет 2 блока с индексом 30 (измененный и исходный).
Как это сделать, не перезаписывая уже измененные индексы?
Хорошо, спасибо, я редактирую свой вопрос для улучшения: как я могу сделать что-то подобное, если у меня есть 2 индекса, например:
(freqBiasL2[32][100])
(SatBiasL1[32][101])
(defSatBiasL2_L1[32][102])
(defSatBiasSlope[32][103])
(defSatBiasSigma[32][104])
и я хочу увеличить только второй индекс, игнорируя первый?
решение1
Используйте perl:
perl -pe 's/(?<=\[)(\d+)(?=\])/$1+1/ge' prova.txt
Объяснение:
-p
означает цикл по каждой строке и вывод результата после каждой строки-e
определяет выражение, которое будет выполняться в каждой строкеs/from/to/
делает простую заменуs/(\d+)/$1+1/ge
сопоставляет одну или несколько цифр, записывает их в$1
, а затемe
модификатор в конце сообщает Perl, что строка подстановки является выражением:$1+1
подставляет значение$1
плюс 1.g
Модификатор означает, что эту подстановку следует выполнять глобально, т. е. более одного раза в строке.(?<=\[)
является положительным утверждением нулевой длины lookbehind. Это означает, что то, что следует за ним, соответствует только если ему предшествует[
(что необходимо экранировать с помощью,\
поскольку[
это специальный токен в регулярных выражениях). Нулевая длина означает, что это не часть того, что будет заменено.(?=\])
является положительным утверждением нулевой длины. Это означает, что то, что идет до него, соответствует только если за ним следует]
(снова экранировано).
Таким образом, это возьмет все числа между [
и ]
и увеличит это число.
решение2
Вы также можете использовать awk
:
awk -F '[\\[\\]]' '{if ($2) { sub($2, $2 + 3)}} 1' prova.txt
На самом деле, это можно немного сократить до:
awk -F '[\\[\\]]' '$2 { sub($2, $2 + 3)} 1' prova.txt
решение3
Я знаю, что вы уже решили свою проблему, но, к вашему сведению, вы могли бы решить ее, внеся очень простую модификацию в свой код: инвертировав последовательность, которую вы перебираете в цикле.
Использование {107..27..-1}
(или, выражаясь короче {107..27}
) было бы достаточным для решения вашей проблемы, поскольку при замене 30 были бы найдены только исходные 30, а 27 еще не были заменены.
решение4
Хорошо, я думаю, что у меня есть решение для двойного индекса, а также изменение команды cas. Это делает работу:
perl -p -e 's/\[(\d+)\]\[(\d+)\]/"[" . ($1) . "][" . ($2+40) . "]"/ge' prova.txt
Кстати, не совсем понимаю, зачем мне нужна эта . ($1) .
(точка с пробелом).