Замена значения значением во втором файле

#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