#bash #shell #sed
#bash #оболочка #sed
Вопрос:
У меня есть два файла. Оба файла представляют собой текстовый текст.
Первый файл содержит строки, по одной на строку.
Второй файл содержит некоторый текст.
Второй файл выглядит следующим образом:
title:
VALUE:
display_name: VALUE
resource:
material: material
generate: false
model_path: model/VALUE
title:
VALUE:
display_name: VALUE
resource:
material: material
generate: false
model_path: model/VALUE
Файл, подобный этому:
einundzwanzig
dreiundzwanzig
vierundzwanzig
fuenfundzwanzig
Мое намерение состоит в том, чтобы это ЗНАЧЕНИЕ заменялось строкой в первой строке три раза. Затем для следующих трех значений вторая строка. И так далее. Я пытался сделать это с помощью bash, но это не сработало.
Итак, я попробовал следующий сценарий:
count=1
# filetwo.txt is your file
cat test.xml | tr "n" "t" > test2.xml
while read line
do
echo $count
echo $line
sed -i " s_value[^<]*value_value$linevalue_${count}; " fileone.txt
((count ))
done < filetwo.txt
cat test2.xml | tr "t" "n" >fileoutput.txt
Но он не хочет работать: (
Комментарии:
1.
<value>
что эти html-теги делают в вашем исходном коде?2. Первоначально я пытался использовать их для XML-файла, но переключился на txt
3. Пожалуйста, добавьте желаемый результат (без описания) для этого примера ввода в свой вопрос (без комментариев).
4. Вы не можете анализировать xml с помощью регулярных выражений — это невозможно. Для редактирования xml используйте инструменты, поддерживающие xml, а не
sed
. И ваш файл выглядит как файл yaml. Обратите внимание, что выsed -i
будете каждый раз заменять значение. Итак, при следующем запуске счетчик неверен, потому что первый уже был заменен. С помощью вашего метода вы хотели бы всегда заменять первое ЗНАЧЕНИЕ.5. что произойдет, если количество
VALUE
строк более чем в три раза превышает количество значений замены?
Ответ №1:
Предположения:
- мы хотим заменить литеральные строки
VALUE
- строка литерала
VALUE
не отображается в более длинной строке (например,DEVALUE
) - количество
VALUE
строк меньше (или равно) в три раза количеству строк замены (т. Е. У нас не закончатся строки замены)
Входные файлы:
$ cat value.template
title:
VALUE:
display_name: VALUE
resource:
material: material
generate: false
model_path: model/VALUE
title:
VALUE:
display_name: VALUE
resource:
material: material
generate: false
model_path: model/VALUE
title:
VALUE:
display_name: VALUE
model_path: model/VALUE
title:
VALUE:
display_name: VALUE
model_path: model/VALUE
$ cat value.dat
einundzwanzig
dreiundzwanzig
vierundzwanzig
fuenfundzwanzig
Одно awk
решение:
awk '
BEGIN { i=1 } # initialize our array counter
# process first file (NR==FNR)
NR==FNR { v[i ]=v[i ]=v[i ]=$1 ; next } # save the replacement string in next 3 array slots
# process second file
FNR==1 { i=1 } # for first line of 2nd file, reset our array counter
/VALUE/ { while ( sub("VALUE",v[i]) ) { i } } # if line includes "VALUE" string then replace each occurrence with next array element referenced by "i"; increment i for next sub()/match
{ print } # print current line
' value.dat value.template
Другое awk
решение, которое сохраняет строки замены только один раз в v[]
массиве:
awk '
BEGIN { i=0 } # initialize array counter
NR==FNR { v[i ]=$1 ; next } # save the replacement string in next array slot
FNR==1 { i=1 } # for first line of 2nd file, reset our array counter
/VALUE/ { while ( sub("VALUE",v[int((i-1)/3)]) ) { i } } # for every 3 instances of "VALUE" replace with the same entry from the v[] array; increment i after each sub()/match
{ print } # print current line
' value.dat value.template
ПРИМЕЧАНИЕ: удалите комментарии к коду declutter
Оба вышеперечисленных генерируют:
title:
einundzwanzig:
display_name: einundzwanzig
resource:
material: material
generate: false
model_path: model/einundzwanzig
title:
dreiundzwanzig:
display_name: dreiundzwanzig
resource:
material: material
generate: false
model_path: model/dreiundzwanzig
title:
vierundzwanzig:
display_name: vierundzwanzig
model_path: model/vierundzwanzig
title:
fuenfundzwanzig:
display_name: fuenfundzwanzig
model_path: model/fuenfundzwanzig
Ответ №2:
Это может сработать для вас (GNU sed):
sed -Ee '1{x;s/^/cat file1/e;x} # copy file1 to hold space
:a;/title:/{ # when line contains title:
:b;n;/title:/{x;s/^[^n]*n//;x;ba} # end of stanza reduce file1
/VALUE/{G;s/VALUE([^n]*)n(S ).*/21/} # replace VALUE
bb}' file2 # repeat
В первой строке скопируйте содержимое file1 в пространство хранения.
Если строка содержит title:
, распечатайте эту строку и извлеките следующую.
Если эта строка содержит title
, удалите первую строку file1 в пространстве хранения и повторите из держателя цикла :a
.
В противном случае, если текущая строка содержит VALUE
, добавьте пробел удержания к текущей строке и замените VALUE
первой строкой в пространстве удержания.
Повторите из держателя цикла :b
.
В качестве альтернативы, просто замените 3 VALUE
поля в file2 для каждой строки в file1:
sed -E '1{x;s/^/sed "p;p" file1/e;x}
:a;/VALUE/{G;s/VALUE([^n]*)n(S ).*/21/;x;s/[^n]*n//;x;ba}' file2