Изменить другое слово при условии слова в той же строке в командной строке?

#linux #shell #unix

#linux #оболочка #unix

Вопрос:

Я получил html файл, который выглядит следующим образом (удалите некоторые ненужные слова).

 <li class="toctree-l1">examples</a></li>
<li class="toctree-l3">charcnn</a></li>
<li class="toctree-l4">cifar10</a></li>
 

Я хочу отредактировать его, не заходя в файл ( sed например, команда). У меня был dict , который

 dict = {'example':l1, 'charcnn':l2, 'cifar10':l3}
 

После dict , html файл должен быть

 <li class="toctree-l1">examples</a></li>
<li class="toctree-l2">charcnn</a></li>
<li class="toctree-l3">cifar10</a></li>
 

Перед заменой это l1 , l3 и l4 . После этого l1 , l2 и l3 .

Я знаю sed , что команда может заменяться ключевыми словами, но она используется для замены текущих слов. Есть ли способ заменить другое слово при условии слова в той же строке?

Комментарии:

1. Данные одинаковы до и после. Что нужно изменить?

2. @RamanSailopal Перед l1, l3 и l4 . После — l1, l2 и l3.

3. Awk — это возможность для этого, но она не идеальна для html / XML. Однако нам понадобится весь полный HTML-файл.

4. html/XML не в этом суть. Вы можете использовать его как файл другого типа ( txt например). Суть в том, можем ли мы заменить другое слово при условии слова в той же строке.

5. Я не понимаю предложение «Я хочу отредактировать его, не заходя в файл (например, команда sed)». Можете ли вы перефразировать или объяснить это, особенно фразу «отредактируйте это, не заходя в файл» ?

Ответ №1:

Конечно sed , можно заменить одну часть строки в зависимости от другой части строки.

Для вашего примера данных вы могли бы использовать

 sed 's#(<li class="toctree-)[^"]*(">examples</a></li>)#1l12#
     s#(<li class="toctree-)[^"]*(">charcnn</a></li>)#1l22#
     s#(<li class="toctree-)[^"]*(">cifar10</a></li>)#1l32#' inputfile
 

Команды проверяют всю входную строку, но допускают все, что находится между toctree- и " .

С этим (измененным) вводом

 <li class="toctree-l1">examples</a></li>
<li class="toctree-l3">charcnn</a></li>
<li class="toctree-l4">cifar10</a></li>
<li class="toctree-something">other</a></li>
<li class="toctree-foo">examples</a></li>
<li class="toctree-bar">charcnn</a></li>
<li class="toctree-baz">cifar10</a></li>
 

вывод

 <li class="toctree-l1">examples</a></li>
<li class="toctree-l2">charcnn</a></li>
<li class="toctree-l3">cifar10</a></li>
<li class="toctree-something">other</a></li>
<li class="toctree-l1">examples</a></li>
<li class="toctree-l2">charcnn</a></li>
<li class="toctree-l3">cifar10</a></li>
 

Если у вас есть параметры для замены в словаре ( dict ), вы могли бы написать некоторый код, который генерирует sed команды из вашего словаря в форме
s#(<li class="toctree-)[^"]*("> key </a></li>)#1 value 2#

В зависимости от ваших потребностей вы можете использовать разные или более короткие шаблоны, такие как

 s#("toctree-)[^"]*(">examples<)#1l12#
 

Редактировать после уточнения вопроса в комментарии:

Чтобы изменить исходный файл, вы можете либо сохранить sed выходные данные в новом файле, а в случае успеха переименовать его в исходное имя файла, например

 sed -e 'sed-command' inputfile > outputfile amp;amp; mv outputfile inputfile
 

или используйте -i опцию (редактирование на месте), если она доступна

 sed -i -e 'sed-command' inputfile
 

(Обратите внимание, что вы можете потерять исходный ввод, если ваша команда содержит ошибку.)

Ответ №2:

 awk -v dict="{'example':l1, 'charcnn':l2, 'cifar10':l3}" '

       BEGIN{ 
                dict1=gensub(/[}{'"'"' ]/,"","g",dict);
                split(dict1,map,",") } 
       /toctree/ {
                cnt  ;
                split(map[cnt],map1,":");
                print "<li class="toctree-"map1[2]"">"map1[1]"</a></li>" }
            ' htmlfile
 

Одна строка:

 awk -v dict="{'example':l1, 'charcnn':l2, 'cifar10':l3}" 'BEGIN{ dict1=gensub(/[}{'"'"' ]/,"","g",dict);split(dict1,map,",") } /toctree/ {cnt  ;split(map[cnt],map1,":");print "<li class="toctree-"map1[2]"">"map1[1]"</a></li>" }' htmlfile
 

Предполагая, что «toctree» больше нигде не существует в htmlфайле, вы можете попробовать выше. Сначала передайте dict в качестве переменной в awk, а затем в блоке begin удалите ненужные символы и используйте функцию split для размещения записей в массиве с именем map . Затем мы ищем любые строки с toctree, увеличиваем счетчик cnt, разделяем запись массива map на map1, используя «:» в качестве разделителя, и печатаем отформатированные строки по мере необходимости.

Печать, несомненно, потребует работы, чтобы обеспечить правильный отступ.

Комментарии:

1. Я предлагаю объяснить ваш awk код. Насколько я понимаю, он не будет проверять ключевые example слова, charcnn … но обрабатывает словарь по порядку независимо от количества и порядка совпадающих входных строк.

2. Да, это то, что я понял как требование. Порядок списка будет зависеть от порядка записей в dict

3. Я предлагаю объяснить это в вашем ответе. Вопрос не совсем ясен в отношении требований. Из названия dict я предположил, что оно подразумевается как словарь, который не обязательно имеет определенный порядок.