Text-Processing

如何使用 sed 搜尋儲存在保持空間中的單詞?

  • October 28, 2015

這是一個sed特定的問題;我很清楚它可以使用其他工具來完成,但我正在努力擴展我對sed.

如何使用sed全域引用(實際上是反引號)腳本中未指定的單詞?單詞被保存在保存空間中。

我想要的是這樣的:

s/word/`&`/g

但訣竅是,word將不包含在 sed 腳本中,而是包含在保留空間中。所以它看起來更像:

H
g
s/^\(.*\)\n\(.*\)\1\(.*\)$/\2`\1`\3/

這將引用保存空間中保存的單詞的一次出現。我想引用所有這些,但我不能只添加一個g標誌,因為它使用反向引用而不是靜態正則表達式。

H
g
s/^\(.*\)\n\(.*\)\1\(.*\)\1\(.*\)$/\2`\1`\3`\1`\4/

這處理了單詞的兩次出現,但一次失敗,並且忽略了不止一次。

我想我可以使用一些乾淨簡單的東西,比如:

s//`&`/g

但這重用了最後使用的regex,而不是它匹配的內容。(這是有道理的。)

有什麼辦法sed可以做我想做的事嗎?(實際上我很想看看這在 中有多容易perl,但我仍然想看看如何在 中做到這一點sed。)


更新

並不是說這個問題需要它,但我想我會在提出這個問題時就我到底在做什麼提供更多背景資訊:

我有一個很大的文件文本文件,其中某些部分需要壓縮並彙總到一個asciidoc表格中。Description:由於和Prototype:線等,這很容易,所以我實際上編寫了一個快速sed腳本來為我完成所有解析。它工作得很好——但它缺少的一件事是我想反引號該Description行中與該行中列出的參數匹配的單詞Prototype。原型線看起來像這樣:

Prototype: some_words_here(and, arg, list,here)

我輸出的表中有超過 200 個不同的條目(源文件包含的文本比這多得多),每個 arglist 只需要用於在單行上反引號引用匹配的單詞。更棘手的是,有些參數不在描述行中,有些在不止一次,有些參數列表是空的()。

但是,考慮到有時 arg 會匹配單詞的一部分,我不想反引號,有時 arg 名稱是一個常用詞(如from),我只想在它用於在解釋函式使用的上下文中,自動化解決方案實際上根本不適合,我過去常常vim在一些棘手的宏的幫助下半手動地完成這項工作。:)

那是一個艱難的過程。假設你有file這樣的:

$ cat file
word
line with a word and words and wording wordy words.

在哪裡:

  • 第 1 行:是應該保留在保留空間中並引用到的搜尋模式word
  • 第 2 行:是全域查找和替換的行。

sed命令:

sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file

說明

  • 1h;將第一行保存到保留空間(這是我們要搜尋的等待)。

    • 容納空間包含:word
  • 2{...}適用於第二行。

  • x;交換模式空間和保持空間。

  • G;將保持空間附加到模式空間。在我們現在擁有的模式空間中:

word # I will call this line the "pattern line" from now on
line with a word and words and wording wordy words.
  • :l;``l為以後設置一個稱為點的標籤。

  • s///在上述模式空間中進行實際搜尋/替換:

    • ^\([^\n]\+\)\n``^在“模式行”中搜尋所有不是換行符[^\n](一次或多次)的字元(從行的開頭\+),直到換行符\n。這現在儲存在 back-reference 中\1。它包含“模式線”。
    • (.*[^])搜尋.*後跟一個字元的任何字元,該字元不是反引號[^]。這儲存在\2. \2包含現在: line with a word and words and wording wordy, 直到最後一次出現word, 因為…
    • \1是下一個搜尋詞(反向引用\1, word),因此是“模式行”包含的內容。
    • ([^])這後面是另一個不是反引號的字元;保存到參考\3。如果我們不這樣做(以及\2上面的部分),我們將在一個無限循環中結束word,一次又一次地引用相同的 -> `````word`````,因為s///總是會成功並tl;跳回:l(見下文tl;`)。
    • \1\n\2\1\3以上所有內容都被反向引用所取代。第二個\1是我們應該引用的(注意第一個引用是“模式線”)。
  • tl;如果s///成功(我們替換了一些東西)跳轉到被呼叫的標籤l並重新開始,直到沒有更多的東西可以搜尋和替換。當所有出現的單詞都被替換/引用時,就是這種情況。

  • p;完成後,列印更改的行(模式空間)。


輸出:

$ sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
word
line with a `word` and `word`s and `word`ing `word`y `word`s.

引用自:https://unix.stackexchange.com/questions/239035