使用sed
的基本解決方案依賴於comm
輸出只在第一個文件中沒有前綴的行;它只輸出第二個文件中只有一個標籤的行;並使用兩個選項卡輸出在兩個文件中找到的行。
它還依靠sed
的w
命令寫入文件。含有
鑑於文件1.sorted.txt
:
1.line-1
1.line-2
1.line-4
1.line-6
2.line-2
3.line-5
和文件2.sorted.txt
含有:
1.line-3
2.line-1
2.line-2
2.line-4
2.line-6
3.line-5
從comm 1.sorted.txt 2.sorted.txt
基本輸出的是:
1.line-1
1.line-2
1.line-3
1.line-4
1.line-6
2.line-1
2.line-2
2.line-4
2.line-6
3.line-5
給出一個包含有一個文件script.sed
:
/^\t\t/ {
s///
w file.3
d
}
/^\t/ {
s///
w file.2
d
}
/^[^\t]/ {
w file.1
d
}
可以運行如下所示的命令,並得到這樣所需的輸出:
$ comm 1.sorted.txt 2.sorted.txt | sed -f script.sed
$ cat file.1
1.line-1
1.line-2
1.line-4
1.line-6
$ cat file.2
1.line-3
2.line-1
2.line-4
2.line-6
$ cat file.3
2.line-2
3.line-5
$
該腳本的工作原理是:
- 與2個選項卡開始匹配行,刪除將行寫入
file.3
,並刪除該行(以便忽略該腳本的其餘部分),
- 匹配以1個選項卡開頭的行,刪除將行寫入
file.2
,並刪除該行(以便忽略該腳本的其餘部分),
- 匹配的行不以選項卡開頭,將行寫入
file.1
,並刪除該行。
步驟3中的匹配和刪除操作比其他任何操作都更對稱;他們可以省略(只留下w file.1
),這個腳本的工作原理是一樣的。不過,請參見下面的script3.sed
,以獲得保持對稱性的進一步理由。
正如所寫,這需要GNU sed
; BSD sed
不能識別\t
轉義。顯然,該文件可以使用實際製表符代替\t
表示法,然後使用BSD sed
即可。
可以使它在命令行上全部工作,但它很煩瑣(而且這對它很有禮貌)。使用bash的ANSI C Quoting,你可以寫:
$ comm 1.sorted.txt 2.sorted.txt |
> sed -e $'/^\t\t/ { s///\n w file.3\n d\n }' \
> -e $'/^\t/ { s///\n w file.2\n d\n }' \
> -e $'/^[^\t]/ { w file.1\n d\n }'
$
這在一個單獨的-e
選項寫入每個script.sed
三個「段落」的。 w
命令很繁瑣;它需要在腳本的同一行之後的文件名和文件名,因此在腳本中的文件名之後使用\n
。有很多可以消除的空間,但是顯示的佈局對稱更清晰。使用-f script.sed
文件可能更簡單 - 它肯定是一種值得了解的技術,因爲它可以避免sed
腳本必須在單引號,雙引號和反引號上操作時出現問題,這使得難以在Bash命令行上編寫腳本。
最後,如果這兩個文件可以包含以製表符開頭的行,這種技術需要更強大的力量才能使其工作。一種變體解決方案利用Bash的process substitution在文件中的行之前添加前綴,然後在處理sed
腳本之前先刪除前綴,然後再寫入輸出文件。
script3.sed
(由多達8個空格代替製表符) - 注意,這時候有在第三段需要一個替代s///
(該d
仍然是可選的,但是也可以被包括在內):
/^ X/ {
s///
w file.3
d
}
/^ X/ {
s///
w file.2
d
}
/^X/ {
s///
w file.1
d
}
和命令行:
$ comm <(sed 's/^/X/' 1.sorted.txt) <(sed 's/^/X/' 2.sorted.txt) |
> sed -f script3.sed
$
對於相同的輸入文件,這產生相同的輸出,但通過添加,然後在每行的開始除去X
,代碼的作用不是C更改數據的排序順序並處理前導標籤(如果它們存在)。
你也可以很容易地編寫使用Perl或Awk的解決方案,甚至不需要使用comm
(如果文件適合內存,也可以使用未分類的文件)。
真棒貢獻。希望我們仍然有SO文檔。爲BSD sed的用戶添加一件事。如果你碰巧在FreeBSD中,你的'/ bin/sh'而不是* bash的Almquist shell包含類似於bash的C風格的引用。 – ghoti
這似乎不起作用,如果我在開始(和單詞之間)在行中添加多個製表符/空格 – RomanPerekhrest
@RomanPerekhrest:您是否在說使用'script3.sed'的變體以及過程替換不起作用數據的行中有前導標籤或多個空格或製表符?如果是這樣,我想看看示例數據。您能否通過電子郵件將它發送給我 - 查看我的個人資料。一個可能的問題是,「sort」和「comm」並不認爲數據按排序順序排列意味着什麼。您可能需要在環境中設置「LANG = C」才能使其工作。 –