Как сделать замену 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]. 
  • Преобразование содержимого файла в нижний регистр и сохранение результата в том же файле
  • Могу ли я использовать `sed` для перевода символов, например, с помощью` tr`?
  • Что делает «текст» точно в Bash? Может ли он использоваться в Zsh?
  • Замените несколько пробелов одним, используя только «tr»
  • Чтобы удалить новые строки после пустой строки
  • Могут ли команды tr быть закодированы, чтобы избежать нескольких tr процессов в конвейере?
  • Почему команда tr не читается из файла?
  • Как я могу распечатать все, кроме последних n символов в bash?
  • Как удалить пробелы из переменных оболочки?
  • tr не заменяет апостроф
  • команда tr не работает с восьмеричными последовательностями
  • Interesting Posts

    Как запустить новую фоновую команду последовательно, если у меня уже есть команда nohup background?

    Совместное использование соединений NetworkManager не похоже на NAT-пакеты

    Есть ли способ отправить почту без сервера ретрансляции?

    Отправка команд на dbx из Vim

    Что касается создания и уничтожения конфиденциальных данных в системах linux / unix

    Правильно ли я понимаю, как символические ссылки и `..` взаимодействуют в POSIX

    как я могу переименовать несколько файлов, удалив символ или строку?

    Does FreeBSD Изменяет MAC-адреса интерфейсов?

    Как вы можете получить ping для печати человекообразных временных меток?

    Ошибка сегментации при попытке запуска glxgears через virtualGL

    Как включить протокол NFS4

    Стереофонический «тональный генератор» для Linux?

    Предупреждения о сценарии Ksh

    X-сервер, запущенный kdm, умирает во время запуска из-за невозможности загрузки ключевой карты

    Как получить s3cmd для установки на CentOS 7.2?

    Linux и Unix - лучшая ОС в мире.