Command-Line

用於輕鬆多行正則表達式搜尋和替換的命令行工具

  • May 20, 2016

在使用文本編輯器時,我經常使用 PCRE 正則表達式進行搜尋和替換,當我發現在強大的 Unix 命令行工具perl中,awk或者sed使用有點高級的多行正則表達式並且需要各種很難記住各種情況的語法。

是否有適用於 Linux 的命令行工具,其中使用更複雜的多行正則表達式進行搜尋和替換(針對整個文件中的所有出現)非常簡單:

magicregextool 's/.* > (.*) joined the channel\.\n(((?!.* \1 (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.*\1 disconnected)/\2/' file.txt

即要匹配的正則表達式與我search for在文本編輯器中的欄位中放置的相同,替換字元串也可以處理多行正則表達式,並且不需要任何復雜的語法?

編輯:

根據請求,我附加了一個輸入,我將使用上面的範例正則表達式來解釋我希望它實際做什麼。

像這樣的輸入:

2016-05-16 06:17:00 > foobar joined the channel.
2016-05-16 06:17:13 <foobar> hi
2016-05-16 06:18:30 > foobar was kicked from channel.
2016-05-16 06:18:30 > foobar disconnected
2016-05-16 06:20:13 > user joined the channel.
2016-05-16 06:20:38 <user> bye
2016-05-16 06:21:57 > user disconnected

應該產生這個輸出:

2016-05-16 06:17:00 > foobar joined the channel.
2016-05-16 06:17:13 <foobar> hi
2016-05-16 06:18:30 > foobar was kicked from channel.
2016-05-16 06:18:30 > foobar disconnected
2016-05-16 06:20:38 <user> bye
2016-05-16 06:21:57 > user disconnected

正則表達式匹配任何包含的行,[username] joined the channel並在其下方查找包含的行,[username] disconnected 除非這兩行之間存在 a[username] was kicked from channel.[username] was banned from channel.

然後,替換字元串用該行之後的每一行替換匹配的模式,並從上面的輸入中[username] joined the channel有效地刪除該行。2016-05-16 06:20:13 > user joined the channel.

很可能對您沒有任何意義,但這只是一個範例正則表達式,類似於我最近處理的一個。請記住,我不是在為這個特定問題或上面列出的 Unix 工具的類似問題尋找解決方案。我正在尋找一個命令行工具,它可以使用我在文本編輯器(特別是 Geany,但這並不重要)中使用的未修改的“搜尋”和替換字元串,而不需要復雜的語法或需要一些額外的程式邏輯來處理多行“搜尋”和替換字元串。

我不確定為什麼 Perl 在這裡不被接受。在您提供的輸入中,這一行給出了您要求的輸出:

perl -0777p -e 's/.* > (.*) joined the channel\.\n(((?!.* \1 (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.*\1 disconnected)/\2/mg' irc.txt

除了我添加了正則表達式修飾符之外,該-e參數正是您的第一個參數。這可能不是“未經修改”,但似乎也不是不合理的。如果您不想輸入整行,那麼這個腳本怎麼樣:magicregextool``/mg``magicregextool

#!/usr/bin/perl -0777p
BEGIN { $::arg = shift @ARGV; }
eval $arg;

甚至:

#!/bin/sh
perl -0777pe $*

然後你只需輸入:

magicregextool 's/.* > (.*) joined the channel\.\n(((?!.* \1 (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.*\1 disconnected)/\2/mg' irc.txt

這與您的範例相同(再次添加/mg修飾符除外)。

這樣做的另一個好處是,如果您在每個文件上執行多個相關的搜尋/替換操作,您可以將它們放在同一個腳本中:

#!/usr/bin/perl -0777p
s/.* > (.*) joined the channel\.\n(((?!.* \1 (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.*\1 disconnected)/\2/mg;
s/(some other\n)matched text/\1/mg;

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