man rsync:
-q, --quiet
This option decreases the amount of information you are given
during the transfer, notably suppressing information messages
from the remote server. This option is useful when invoking
rsync from cron.
Комплекс bash + sed решение:
foobar_replacer.sh скрипт:
#!/bin/bash
head -n1 "$2" # print the first line
while read -r line
do
sed '1d;$d;{s/^foo bar$/'"$line"'/g}' "$2"
done < "$1"
tail -n1 "$2" # print the last line
Использование :
bash foobar_replacer.sh foobar.txt input.txt
Вывод:
some text …
% BEGIN
blabla
2 3
blabla
blabla
% END
% BEGIN
blabla
8 9
blabla
blabla
% END
% BEGIN
blabla
1 2
blabla
blabla
% END
some text …
sed подробности команды:
1d;$d;
- удалить первую и последнюю строку из input.txt
s/^foo bar$/'"$line"'/g
- заменить строку, содержащую foo bar
, на следующий элемент $line
из foobar.txt
Попробуйте это:
while read line; do awk -v f="$line" '{gsub(/foo bar/, f)} 1' input; done <foobar.txt
Это читает строку за строкой из foobar.txt
. Для каждой строки
в foobar.txt
считывается файл input
и строка
из foobar.txt
. заменяется для каждого вхождения foo bar
.
при чтении строки; do
Это запускает цикл while
, который читает строки из foobar.txt.
awk -vf="$line" '{gsub(/foo bar/, f)} 1' input
Это читает файл input
и заменяет в $line
везде, где встречается foo bar
.
Более подробно:
-v f="$line"
Это создает переменную awk f
, значением которой является содержимое переменной оболочки line
.
gsub(/foo bar/, f)
Для каждой строки, которую awk считывает, ищет вхождения регулярного выражения foo bar
и подставляет значение f
1
Это сокращение от awk для печати строки.
Причина использования здесь awk, а не sed, заключается в том, что awk лучше обрабатывает значения переменных оболочки.
done
Это сигнализирует об окончании цикла while
и указывает циклу использовать файл foobar.txt
в качестве стандартного ввода.
Для тех, кто любит раскидывать команды на несколько строк:
while read line
do
awk -v f="$line" '{gsub(/foo bar/, f)} 1' input
done <foobar.txt
perl -nMFatal=open -e '$l = $_;
@ARGV and open my $fh, "<", $ARGV[0];
print +(/^%\hBEGIN/ ? $a=0 : $a++) == 1 ? $l : $_ while <$fh>;
' foobar.txt input.txt
открываем
лексический
дескриптор файла $fh
для файла input.txt. Причина, по которой он должен быть лексическим, заключается в том, что он закрывается сам по себе, когда считывается следующая строка ввода из foobar.txt. $a
, когда видим % Строка BEGIN
в файле input.txt. И через 1 строчку после этого заменяем строчку в input.txt на строчку из foobar.txt. some text --
% BEGIN
blabla
2 3
blabla
blabla
% END
some text --
some text --
% BEGIN
blabla
8 9
blabla
blabla
% END
some text --
some text --
% BEGIN
blabla
1 2
blabla
blabla
% END
some text --
Вот способ сделать это на чистом awk, используя getline
:
awk '
/% BEGIN/ {
s = 1;
}
s == 1 {
b = b == "" ? $0 : b ORS $0
}
/% END/ {
while ((getline repl < "foobar.txt") > 0) {
tmp = b;
sub(/foo bar/, repl, tmp);
print tmp;
}
b = "";
s = 0;
next;
}
s == 0 {
print;
}' input
С помощью GNU awk вы можете сделать замену без временного использования – используя gensub
:
gawk '
/% BEGIN/ {
s = 1;
}
s == 1 {
b = b == "" ? $0 : b ORS $0
}
/% END/ {
while ((getline repl < "foobar.txt") > 0) {
print gensub(/foo bar/, repl, 1, b);
}
b = "";
s = 0;
next;
}
s == 0 {
print;
}' input
Тестирование :
$ gawk '
> /% BEGIN/ {s = 1;}
> s == 1 {b = b == "" ? $0 : b ORS $0}
> /% END/ {while ((getline repl < "foobar.txt") > 0) {print gensub(/foo bar/, repl, 1, b);} s = 0; next;}
> s == 0 {print}' input
some text …
% BEGIN
blabla
2 3
blabla
blabla
% END
% BEGIN
blabla
8 9
blabla
blabla
% END
% BEGIN
blabla
1 2
blabla
blabla
% END
some text …
sed -e '
1{
:loop
N
/\n\.$/!bloop
s///;h
N;s/.*\n//
}
G
y/\n_/_\n/
s/^\([^_]*\)_\(.*_% BEGIN_[^_]*_\)[^_]*/\2\1/
y/\n_/_\n/
' input.txt foobar.txt
sed
не имеет представления о том, когда заканчивается один файл и начинается следующий, нам нужно либо добавить eof Различение -, скажем, .
, ИЛИ основываясь на типе данных в двух файлах. файлов, чтобы определить, в каком файле мы находимся. В нашем случае я выбираю первый метод. % BEGIN
в пространстве шаблонов на первую строку. Примечание :У нас есть то, что multiline pattern space
, что такое...\n...\n...\n...
bash
скрипт с использованием sed
. Использование :./search_and_replace.sh < input.txt
, результат будет в новом output.txt
файле
#!/bin/bash
begin_str="% BEGIN"
end_str="% END"
pattern="foo bar"
write_to_var_flag=0
output_file=output.txt
foobar_file=foobar.txt
begin_to_end_block_var=""
# clean output file if it exist, else create it
> "$output_file"
function read_foobar_file () {
while read -r line; do
echo -ne "$begin_to_end_block_var" | sed "s/$pattern/$line/" >> "$output_file"
done < "$foobar_file"
}
while read -r line; do
if [ "$line" == "$begin_str" ]; then
write_to_var_flag=1
fi
if (( $write_to_var_flag )); then
begin_to_end_block_var+="$line\n"
else
echo "$line" >> "$output_file"
fi
if [ "$line" == "$end_str" ]; then
read_foobar_file
write_to_var_flag=0
fi
done