Подсчитать и вернуть, сколько замен было сделано с помощью sed в файле

Вы можете скопировать только второй раздел в отдельный образ с помощью этого

dd if=2013-02-09-wheezy-raspbian.img of=second.img bs=512 skip=122880

и после этого можно скопировать вместо раздела на диске

dd if=second.img of=/dev/sdc2 bs=512

или даже одной командой

dd if=2013-02-09-wheezy-raspbian.img of=/dev/sdc2 bs=512 skip=122880

Просто убедитесь, что вы размонтировали /dev/sdc2 перед записью в него.

4
09.11.2021, 10:50
5 ответов

Если вы должны использовать sed, то одним из способов может быть

Согласно предложениям @Phillipos, он изменен на:

sed -i "" -e '
  s/my_string/new_string\
/g;s/\n//w /dev/stdout
  s///g
' my_file.json | wc -l
  • поместите новую строку после каждого вхождения моей строки _+ также внесите изменения.
  • затем удалите одну новую строку, так как sed неявно помещает ее при печати.
  • запись в stdout происходит условно, только когда подстановка прошла успешно, то есть когда в этой строке была моя _строка mng
  • затем мы убираем маркеры новой строки.
6
09.11.2021, 12:52

Вы можете заставить редактор vim создавать отчеты в потоковом режиме:

ex -nsc 'redir! >/dev/stderr' -c '%s/pattern/PATTERN/g' -c 'redir END' -c 'wq' my_file

3 substitutions on 2 lines

ex-режим vim (илиvim -e)
-n-не создавать файл подкачки
-s-скрипт
-cрежим командной строки (или+'command')
'redir! >/dev/stderr'-стандартная ошибка перенаправления в оболочку
'redir END'-конец перенаправления. Можно опустить
'wq'-сохранить изменения и выйти из редактора. Если вы замените его на 'q!', то сможете получить вывод и сравнить с ожиданиями, не меняя файл.

4
09.11.2021, 12:15

sed не считает ничего, кроме номеров строк. Поэтому, если вы хотите использовать sedи не использовать другие инструменты, как это сделал guest _7, вам нужно научить его считать :

.
sed -n -i"" ':start
  s/my_string/new_string/
  Tcont
  H
  bstart
  :cont
  p
  $!d
  x
  y/\n_/_\n/
  s/_[^_]*/-/g
  s/^/0123456789+_0/
  :loop
  s/\(.\)\(.\)\(.*_.*\)\1-/\1\2\3\2/
  s/_+/_10/
  s/\(.\)\(.\)\(.*_.*\)\1+/\1\2\3\20/
  tloop
  s/.*_//
  w/dev/stdout
  d' my_file.json

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

3
09.11.2021, 14:10

Это голая -версия awk для подсчета изменений и затронутых строк:

#! /bin/bash

Awk='
BEGIN { fmtEnd = "Made %d substitutions on %d lines.\n"; }
{
    n = gsub (/exit/, "return");
    if (n) { Lines++; Count += n; }
    print;
}
END { printf (fmtEnd, Count, Lines) > "/dev/stderr"; }
'
    awk "${Awk}" doFifo > doFifo.fix

Вывод (stderr )— это просто то, что можно изменить, чтобы упростить восстановление счетчика:

Made 8 substitutions on 6 lines.

GNU/awk имеет расширение -i inplace, но я крайне -консервативен в отношении обновления -in -situ. Мои клиенты много жалуются и утверждают, что их данные всегда на 100% верны, поэтому я храню журналы аудита и каждую версию данных.

Ниже приведен вариант awk, который отмечает каждую измененную строку. Это все еще не производственный уровень :. Я бы хотел, чтобы он принимал шаблон и замену в качестве аргументов, обрабатывал несколько файлов за один запуск, называл выходные файлы на основе входных данных и суммировал по файлам и в целом. Возможно, также разрешите замену массива шаблонов ->.

#! /bin/bash

AwkFull='
BEGIN {
    reFix = "exit"; txFix = "return";
    fmtEnd = "Made %d substitutions on %d lines.\n";
    fmtSub = "\n.... %d Changes on file %s line %d:\n";
    fmtSub = fmtSub "Was: %s\nNow: %s\n";
}
{
    New = $0;
    n = gsub (reFix, txFix, New);
    if (n == 0) { print $0; next; }

    Lines++; Count += n;
    printf (fmtSub, n, FILENAME, FNR, $0, New) > "/dev/stderr";
    print New;
}
END { printf (fmtEnd, Count, Lines) > "/dev/stderr"; }
'
    awk "${AwkFull}" doFifo > doFifo.fix

Это показывает каждую измененную строку, например:

.... 2 Changes on file doFifo line 64:
Was:    (exit)  printf 1>&7 '%(%T)T  Received exit command\n' -1
Now:    (return)    printf 1>&7 '%(%T)T  Received return command\n' -1

Правка :Преобразование параметров в аргументы команды.

В первой версии шаблон и замещающий текст были встроены в саму команду gsub. Вторая версия упростила их изменение, (a )дав им имена и (b )объявив их в начале кода.

Следующим этапом обобщения кода будет их передача из оболочки. Это легко в awk. Во-первых, удалите строку, определяющую соглашение reFix и txFix (: reдля регулярного выражения и txдля текста, но вызывайте переменные как угодно, если вы согласны ).

Чтобы получить строки оболочки в переменные awk, существует опция -v. Таким образом, ваша команда awk становится:

awk -v reFix="exit" -v txFix="return" "${AwkFull}" doFifo > doFifo.fix

и последним шагом к использованию переменных оболочки является использование любой формы подстановки оболочки, например:

awk -v reFix="${1}" -v txFix="${myNew}" "${AwkFull}" doFifo > doFifo.fix

Есть два (а может и больше )минусов:

(1 )awk знает, что /exit/— это шаблон. В некоторых случаях может потребоваться пояснение синтаксиса :, например,простое совпадение строки -типа /exit/нужно будет переписать как $0 ~ reFix. Но awk знает, что первый аргумент gsub()— это шаблон, так что синтаксис работает без изменений. (Подробнее см. https://www.gnu.org/software/gawk/manual/gawk.html#Strong-Regexp-Constants.)

(2 )Шаблоны в переменных не проверяются синтаксис -при первом чтении программы awk, только когда они используются. Таким образом, введенные пользователем -шаблоны могут легко сломаться в середине выполнения и с неясными сообщениями об ошибках.

2
11.11.2021, 10:50

Использование Raku (, ранее известного как Perl _6)

raku -pe 'state $k += s:g/ old_string /NEW_STRING/; END put $k;'

ИЛИ

raku -pe 'state $k; s:g/ old_string{++$k} /NEW_STRING/; END put $k;'

Выше приведено решение, написанное на Raku, члене семейства языков программирования Perl. Первое решение — это довольно прямой перевод кода Perl (5 )@terdon, опубликованного в другом месте этой ветки. Второе решение демонстрирует способность Raku выполнять код в блоках {...}, внутри сопоставителя регулярных выражений m/.../и/или подстановок s///. Оба примера записывают количество замен, выполненных в последней строке файла/вывода.

Кратко, rakuвызывается из командной строки с флагами автопечати-pe(построчно ). Переменная $kинициализируется ключевым словом state, что означает, что она объявляется только один раз во время выполнения. После объявления stateзначение $kможет быть увеличено либо оператором +=(, первый пример ), либо оператором приращения ++$k, предшествующим -, (, вторым примером ). ]. Обратите внимание, что :в левой -половине (, но не в правой -половине )пробела сопоставителя Раку s///не имеет значения, поэтому вы можете свободно размещать элементы регулярного выражения (для улучшения читаемость ).

И Raku, и Perl (5 )имеют нулевой -индекс, поэтому подсчет в цикле автопечати начинается с нуля. Однако у Raku есть некоторая дополнительная гибкость, если вы отбросите -peфлаги автопечати и используете -eс подпрограммой for lines()вместо :, вы можете выбрать начальное значение вашего счетчика. Допустим, вы хотите выполнить 10 замен :, вы можете взять приведенный ниже код, установить $k=10и уменьшить с помощью --$k,проверка последней строки файла, чтобы увидеть, достигли ли вы нуля:

raku -e 'state $k=10; for lines() {S:g/ old_string{--$k} /NEW_STRING/.put; END put $k};'

[Дополнение :Мне не совсем понятно в цикле автопечати raku -pe '', почему state $k=10;не сохраняет, а затем увеличивает/уменьшает начальное значение (в настоящее время поведение должно начинаться с нуля независимо ). Я обновлю этот ответ, как только получу отзыв по этой проблеме].

https://docs.raku.org/syntax/state
https://raku.org

1
11.11.2021, 16:55

Теги

Похожие вопросы