Заменить строку последовательным индексом

Может ли кто-нибудь предложить элегантный способ сделать это?

Входные данные:

test instant () test instant () ... test instant () //total 1000 lines 

выход должен быть:

 test instant1 () test instant2 () test instant1000() 

Пустые строки находятся в моих входных файлах, и есть много файлов в одном каталоге, которые мне нужно обрабатывать сразу.

Я попробовал это, чтобы заменить многие файлы в одном каталоге и не работал.

 for file in ./*; do perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done 

ошибки:

 Substitution replacement not terminated at -e line 1. Substitution replacement not terminated at -e line 1. 

и я также пробовал это: perl -i -pe 's/instant/$& . ++$n/ge' *.vs perl -i -pe 's/instant/$& . ++$n/ge' *.vs

Он работал, но индекс просто увеличивался от одного к другому. Я хотел бы сбросить его до 1 для файла diff. любые хорошие предложения?

 find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} + 

но он заменил все другие файлы, которые не должны быть заменены. Я предпочитаю просто заменять файлы только «* .txt».

  • Как взять список и удалить его из файла?
  • Преобразование простых данных в json-файл
  • Удалите все повторяющиеся слова из строки, используя сценарий оболочки
  • Найдите строку (например, grep -q) только в одном разделе файла
  • сценарий оболочки для извлечения символов
  • Сценарий Bash - части chomp из строки
  • Катить все файлы в папке, включая имя файла, используя цикл for?
  • sed: многострочная замена блока конфигурации
  • 2 Solutions collect form web for “Заменить строку последовательным индексом”

     perl -pe 's/instant/$& . ++$n/ge' 

    или с GNU awk :

     awk -vRS=instant '{$0=n$0;ORS=RT}++n' 

    Чтобы редактировать файлы на месте, добавьте параметр -i в perl :

     perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' ./* 

    Или рекурсивно:

     find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} + 

    Пояснения

     perl -pe 's/instant/$& . ++$n/ge' 

    -p – обрабатывать ввод строки за строкой, оценивать выражение, переданное -e для каждой строки, и печатать его. Для каждой строки мы подставляем (используя оператор s/re/repl/flags ) для себя ( $& ) и добавочное значение переменной ++$n . Флаг g должен сделать замену глобально (не только один раз), а e чтобы замена интерпретировалась как Perl-код для оценки e (не фиксированная строка).

    Для редактирования на месте, где один вызов perl обрабатывает более одного файла, мы хотим, чтобы $n перезагружался в каждом файле. Вместо этого мы используем $n{$ARGV} (где $ARGV$ARGV обработанный файл).

    awk заслуживает некоторого объяснения.

     awk -vRS=instant '{$0=n$0;ORS=RT}++n' 

    Мы используем способность GNU awk отделять записи от произвольных строк (даже регулярных выражений). Когда -vRS=instant , мы устанавливаем разделитель записи на instant . RT – это переменная, которая содержит то, что соответствовало RS , так обычно, instant за исключением последней записи, где она будет пустой строкой. На входе выше записи ( $0 ) и терминаторы записи ( RT ) являются ( [$0|RT] ):

     [test |instant][ () test |instant][ () ... test |instant][ () //total 1000 lines|] 

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

    Это то, что мы делаем выше. Для первой записи n будет пустым. Мы устанавливаем ORS ( разделитель выходной записи ) в RT, так что awk печатает n $0 RT . Он выполняет это на втором выражении ( ++n ), которое является условием, которое всегда оценивает значение true (ненулевое число), и поэтому для каждой записи выполняется действие по умолчанию (для печати $0 ORS ).

    sed действительно не лучший инструмент для работы, вам нужно что-то с лучшими возможностями сценариев. Вот несколько вариантов:

    • Perl

       perl -000pe 's/instant/$& . $./e' file 

      -p означает «печатать каждую строку» после применения любого скрипта с -e . -000 включает «режим абзаца», поэтому записи (строки) определяются последовательными символами новой строки ( \n ), это позволяет правильно обрабатывать строки с двойным интервалом. $& – последний сопоставленный шаблон и $. – текущий номер строки входного файла. e in s///e позволяет оценить выражения в операторе подстановки.

    • awk (это предполагает, что ваши данные точно такие, как показано, с тремя полями, разделенными пробелами)

       awk '{if(/./) print $1,$2 ++k,$3; else print}' file 

      Здесь мы увеличиваем k переменную k только в том случае, если текущая строка не пуста /. / И в этом случае мы также печатаем необходимую информацию. Пустые строки печатаются как есть.

    • различные раковины

        n=0; while read -rabc; do if [ "$a" ] ; then (( n++ )) printf "%s %s%s %s\n" "$a" "$b" "$n" "$c" else printf "%s %s %s\n" "$a" "$b" "$c" fi done < file 

      Здесь каждая строка ввода автоматически разбивается на пробелы, а поля сохраняются как $a , $b и $c . Затем в цикле $c увеличивается на 1 для каждой строки, для которой $a не пуст, и текущее значение печатается рядом со вторым полем, $b .

    ПРИМЕЧАНИЕ. Все вышеупомянутые решения предполагают, что все строки в файле имеют один и тот же формат. Если нет, @ ответ Стефана – это путь.


    Для работы со многими файлами и при условии, что вы хотите сделать это со всеми файлами в текущем каталоге, вы можете использовать это:

     for file in ./*; do perl -i -000pe 's/instant/$& . $./e' "$file"; done 

    ОСТОРОЖНО: это предполагает простые имена файлов без пробелов, если нужно иметь дело с чем-то более сложным, идите (предполагая ksh93 , zsh или bash ):

     find . -type f -print0 | while IFS= read -r -d ''; do perl -i -000pe 's/instant/$& . $./e' "$file" done 
    Interesting Posts
    Linux и Unix - лучшая ОС в мире.