Как сделать замену sed (s /// g) на основе списка? Мне нужно поменять несколько слов, с другими соответствующими словами

Я не думаю, что этот вопрос задавали раньше, поэтому я не знаю, способен ли sed на это.

Предположим, у меня есть куча чисел в предложении, которое мне нужно развернуть в словах, практическим примером является замена пронумерованных цитат в типичном эссе в формате MLA:

essay.txt :

 Sentence 1 [1]. sentence two [1][2]. Sentence three[1][3]. 

Key.txt (это файл с разделителями табуляции):

 1 source-one 2 source-two 3 source-three ...etc 

Ожидаемый Result.txt :

 Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three] 

Вот моя попытка псевдокода, но я недостаточно понимаю о sed или tr чтобы сделать это правильно:

  cat essay.txt | sed s/$(awk {print $1} key.txt)/$(awk {print $2} key.txt)/g 

PS: Если есть трюк в блокноте ++ для массового поиска и замены с использованием нескольких терминов, это было бы здорово. Как бы то ни было, похоже, что find-and-replace работает только для одного термина за раз, но мне нужен способ сделать это в массовом порядке для многих условий сразу.

3 Solutions collect form web for “Как сделать замену sed (s /// g) на основе списка? Мне нужно поменять несколько слов, с другими соответствующими словами”

awk может сделать то же самое, что и perl здесь немного проще , хотя реализации, отличные от GNU, могут потратить немного времени на процессор, ненужно разбивая текстовый файл (большой?):

 awk 'NR==FNR{a["\\["$1"\\]"]="["$2"]";next} {for(k in a) gsub(k,a[k]);print}' key.txt essay.txt 

Поскольку вы попросили объяснить :

  • awk работает, беря «скрипт», состоящий из пар шаблонов действий, затем считывает один или несколько файлов (или стандартный ввод) одной «записью» в то время, когда по умолчанию каждая запись является строкой, а для каждой записи разбивается на поля по умолчанию в пробеле (который включает в себя вкладку) и применяет сценарий поочередно (если не указано иное), проверяя каждый шаблон (который часто смотрит на текущую запись и / или его поля), и если он соответствует выполнению действия (что часто что-то делает к или с указанной записью и / или полями). Здесь я указываю два файла key.txt essay.txt чтобы он key.txt essay.txt эти два файла в этом порядке, по очереди. Сценарий можно поместить в файл, а не в командной строке, но здесь я решил не делать этого.

  • первый шаблон – NR==FNR . NR – встроенная переменная, которая является номером обрабатываемой записи; FNR аналогично номеру записи в текущем входном файле. Для первого файла ( key.txt ) они равны; для второго файла (и любых других) они неравны

  • первое действие – {a["\\["$1"\\]"]="["$2"]";next} . awk имеет «ассоциативные» или «хешированные» массивы; arrayname[subexpr] где subexpr является subexpr выражением, которое считывает или задает элемент массива. $number например $1 $2 т. д., ссылаются на поля, а $0 ссылаются на всю запись. key.txt это действие выполняется только для строк в key.txt поэтому, например, в последней строке этого файла $1 равно 3 и $2 является source-three , и в этом случае сохраняется запись массива с индексом \[3\] и содержимым [source-three] ; см. ниже, почему я выбрал эти значения. "\\[" и "\\]" являются строковыми литералами, использующими escapes, фактическими значениями которых являются \[ и \] тогда как "[" "]" просто [ ] , а строковые операнды без оператора между ними объединены. Наконец, это действие выполняется next что означает пропустить остальную часть скрипта для этой записи, просто вернитесь к вершине цикла и начните с следующей записи.

  • второй шаблон пуст, поэтому он соответствует каждой строке во втором файле и выполняет действие {for(k in a) gsub(k,a[k]);print} . Конструкция for(k in a) создает цикл, подобный оболочкам типа Bourne, for i in this that other; do something with $i; done for i in this that other; do something with $i; done за исключением того, что здесь значения k являются индексами массива a . Для каждого такого значения он выполняет gsub (глобальный заменитель), который находит все совпадения данного регулярного выражения и заменяет их данной строкой; Я выбрал индексы и содержимое в массиве (выше), так что, например, \[3\] является регулярным выражением, которое соответствует текстовой строке [3] а [source-three] – текстовая строка, которую вы хотите заменить для каждого такого совпадение. По умолчанию gsub работает с текущей записью $0 . После выполнения этой подстановки для всех значений в a она выполняет print которая по умолчанию выводит $0 как она сейчас стоит, со всеми желаемыми заменами.

Примечание: GNU awk (gawk), который обычно встречается в Linux, но не универсален, имеет оптимизацию, где он фактически не выполняет разбиение полей, если ничто в шаблонах или действиях не требует значений полей. В других реализациях небольшое количество процессорного времени может быть потрачено впустую, что предотвращает использование perl метода cuonglm, но если ваши файлы не являются большими, это, вероятно, даже не будет заметным.

Вместо этого вы должны использовать perl :

 $ perl -ne ' ++$nr; if ($nr == $.) { @w = split; $k{$w[0]} = $w[1]; } else { for $i (keys %k) { s/(\[)$i(\])/$1.$k{$i}.$2/ge } print; } close ARGV if eof; ' key.txt essay.txt Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three] 
 bash$ sed -f <( sed -rn 's#([0-9]+)\s+(.*)#s/\\[\1]/[\2]/g#p' key.txt ) essay.txt Sentence 1 [source-one]. sentence two [source-one][source-two]. Sentence three[source-one][source-three]. 
  • Является ли историческое поведение команды Unix V5 tr дополнением set2 отличным от того, что мы считаем сегодня «классическим» поведением System V (1983-1988)?
  • Как получить число знаков препинания из файла
  • Как отображать каждый день месяца в отдельной строке с помощью tr, sed и cal
  • Сделать статистику биграмм
  • Есть ли библиотека или инструмент для «перевода» строки с одного раскладки клавиатуры на другой?
  • SED, чтобы найти и заменить точное слово, начинающееся с $
  • Могу ли я использовать `sed` для перевода символов, например, с помощью` tr`?
  • Генерирование случайного пароля; почему это не переносится?
  • Вытягивание IP-адреса из команды ping с помощью sed?
  • Как префикс обратной косой черты для вывода
  • Замените несколько пробелов одним, используя только «tr»
  • Как удалить все строки с «.png» в файле?
  • Linux и Unix - лучшая ОС в мире.