Учитывая, что вы хотите удалить ~~adt(something)~~
и что ~~(something different)~~
может быть в других строках (, не показанных в вопросе):
$ sed 's/~~adt[^~]*~~//g' file.in >file.out
Для заданных данных будет сгенерировано
478|14395189_p0.jpg
479|44836628_p0.jpg
480|Miku_Collab_2_by_Luciaraio.jpg
Изменив adt
последней строки на xxx
, команда генерирует
478|14395189_p0.jpg
479|44836628_p0.jpg
480|~~xxx00000aae~~Miku_Collab_2_by_Luciaraio.jpg
Шаблон ~~adt[^~]*~~
будет соответствовать всем вхождениям ~~adt
, за которыми следует любое количество символов, кроме ~
, а затем снова ~~
. /g
в конце гарантирует, что все такие совпадения в каждой строке будут удалены.
Предположим, что вы хотите сказать:
У меня есть длинный файл с несколькими счетами. Каждый счет начинается с текста 70 spaces and a 1
. Мне нужно вставить новый контент за 9 строк до этого для каждого счета
Тогда вам нужно накопить 10 строк. Когда текущая строка соответствует началу счета-фактуры , вставьте в первую строку новый текст.
На практике это приводит к тому, что:
sed -e '1{N;N;N;N;N;N;N;N}' -e 'N;l;/\n \{70\}1$/{iNew content here' -e 'P};P;D' file
Или, в полной форме (комментарии не работают в некоторых реализациях sed):
sed '1{ # (only) on the first line
N;N;N;N;N;N;N;N # accumulate 9 lines (first one plus 8 more).
}
N # On every line,also accumulate that line
/\n \{70\}1$/{ # If buffer ends ($) in 70 spaces and a "1"
i\
New content added here # insert the content of this line at
# the start of the buffer (10 lines above).
P # and then print it.
}
P;D # close the N cycle above by
# printing and deleting one line
' file # On the selected file.
Решение awk
может использовать преимущества установки RS на строку, которая отмечает начало счета. В этом случае установка FS на символ новой строки разбивает каждую строку на поле, а $ (NF -9 )будет ссылаться на строку на 9 строк выше:
awk -v ln=9 '
( NF < ln ){ print; next }; # not enought fields?
# include
{ $(NF-ln) = "New Text to include" newln $(NF-ln);
print # and print
};
BEGIN{ breakln = sprintf("%71s",1); # 70 spaces and a 1
newln = sprintf("\n"); # a newline
RS = breakln newln; # set the Record Separator
FS = "\n"; # set the Field separator
OFS = FS; # print what got removed
ORS = RS # print what got removed
}
' file
Или, альтернативно, (решение оболочки/awk):
breakln="$(printf '%71s' 1)";
newl=$'\n';
awk ' (NF<ln){print;next};
{ $(NF-ln)="New Text to include\n"$(NF-ln); print}' \
ln=10 \
RS="$breakln$newl" \
FS="$newl" \
OFS="$newl" \
ORS="$breakln$mewl" \
file
Вот решение -редактора с поддержкой сценариев. Идея состоит в том, чтобы узнать, сколько счетов в файле, основываясь исключительно на количестве строк «(70 пробелов )1» в файле. Затем сценарий повторяется столько раз и выводит команды для ed
. Цикл выводит достаточно команд, чтобы изменить каждую «9-ю строку перед той, в которой есть ' (70 пробелов )1 '», чтобы вместо этого была пунктирная линия обрезки. Замените текст -----8<-----
чем угодно, кроме голой начальной точки (, которую ed
использует для обозначения конца строки замены. Если мы находимся в середине цикла по счетам (i < count
), пропустите 10 строк вперед после внесения изменений, чтобы мы не обнаружили страницу, которую мы только что вырезали. Если мы завершили цикл (i == count
), распечатайте команды ed «записать и выйти». Весь этот вывод printf/echo поступает в конвейер, который ed
считывается как ввод. Опция -s
предназначена для «тихого» режима.--ed
не будет сообщать о количестве прочитанных или записанных байтов.
#!/usr/bin/bash
count=$(grep -c '^ 1' input)
for((i=1; i<=count; i++))
do
printf '%s\n' '/^ 1/-9c'
printf '%s\n' '-----8<-----' '.'
[[ $i < $count ]] && printf '%s\n' '+10'
[[ $i == $count ]] && echo wq
done | ed -s input
С awk
+tac
:
tac file | awk -v delim="--split page here--" '{
if (nextnr=="" && $1~/^[0-9]+$/ && $0==" "$1) {
nextnr=NR+9 # pagenr found, remember next position
}
else if (NR==nextnr) {
$0=delim # overwrite line with delimiter
nextnr="" # reset
}
print
}' | tac
Сначала переверните файл с помощью tac
, чтобы мы могли искать сверху -вниз номер страницы и вставлять разделитель.
Поиск начинается в предложении if -, когда выполняются эти условия.:
nextnr
равно (изначально )не установлено(nextnr==""
). Это переменная, содержащая номер строки следующего разделителя.$1~/^[0-9]+$/
)Если все три условия истинны, nextnr
устанавливается на текущий номер строки (количество записей)NR + 9
.
Если текущая строка является строкой разделителя (NR==nextnr
), перезапишите строку разделителем и сбросьте nextnr
.
Последняя строка скрипта выводит текущую строку (оригинала или перезаписывает разделитель ).
На последнем шаге выход снова реверсируется с помощью tac
.