GNU sed是一款文本流編輯器(stream editor),USEFUL ONE-LINE SCRIPTS FOR SED通过命令sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'實現字符串逆序排列(功能類似於rev)。網路上已有對該命令的解釋

本文主要討論該操作的實現過程。

Command Explanation

sed的官方文件見 sed, a stream editor,命令

1
2
3
4
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'

# 改寫後形式
sed -r '/\n/!G;[email protected](.)(.*\n)@&\2\[email protected];//D;[email protected]@@'

使用到的指令定義如下

  1. G: append hold space to pattern space
  2. D: delete text in the pattern space up to the first newline

!表是取反,;用於分隔操作,順序執行。

//表示使用正則匹配,如果//中不包含任何內容,只是單純的//,則表示最近一次使用正則匹配到的內容。官方說明見:

The empty regular expression // repeats the last regular expression match (the same holds if the empty regular expression is passed to the s command). Note that modifiers to regular expressions are evaluated when the regular expression is compiled, thus it is invalid to specify them together with the empty regular expression. –4.3 selecting lines by text matching

圓括號()之前的反斜線\表示轉義,如果使用-r,則無需使用\進行轉義。

Step 1

/\n/!G表示對不含有換行符\n的數據行,將 hold space 中的內容追加到 pattern space ,如果 hold space 爲空,則相當於在每行的下一行添加了一空行。

Step 2

s/\(.\)\(.*\n\)/&\2\1/表示通過正則查找匹配內容並實現替換。.表示任意不爲\n的單個字符,.*表示任意多個不爲\n的單個字符(>=0)。\(.\)\(.*\n\)用圓括號包裹起來表示稍後爲用到,分別對應其後的\1\2,這種使用方式叫back-reference,具體見官方文檔5.7 Back-references and Subexpressions

此處字符 & 非常重要,表示最近一次使用正則匹配到的內容,即命令中的\(.\)\(.*\n\)(或\1\2),爲匹配到的內容則仍按最開始的位置顯示。例如字符串dcba,第一次作用後的格式爲dcba\ncba\nd,經過//D作用,第二次的格式是cba\nba\cd,第二次作用後顯示的內容中,最後一個字符d是未用正則匹配到的內容,照常顯示,即第二次的&\2\1cba\nba\c,輸出的內容加上未被匹配到的字符d,形成cba\nba\cd,這非常重要。

Step 3

//D是4個步驟中最爲重要的步驟,上文簡要介紹過,單純的//表示最近一次使用正則匹配到的內容\(.\)\(.*\n\)(或\1\2)。即//等同於/\(.\)\(.*\n\)/。字符D表示刪除 pattern space 中第一個\n之前的內容,如dcba\ncba\nd///dcba\n/,經//D作用後爲cba\nd

//D會對字符串進行 循環 操作,操作命令即前一個命令s/\(.\)\(.*\n\)/&\2\1/。當無匹配內容時,則跳出開始執行下一個命令。

Step 4

s/.//表示刪除行首爲newline字符串的行,可理解爲是空行。

Divided Process

構建文件/tmp/sed.txt,內容如下

1
4321

分解過程如下

count s/\(.\)\(.*\n\)/&\2\1/ //D
1 4321\n321\n4 321\n4
2 321\n21\n3+4 21\n34
3 21\n1\n2+34 1\n234
4 1\n\n1+234 \n1234

生成的字符串\n1234經過s/.//處理得到1234

實例演示

1
2
3
4
5
6
7
8
9
10
11
12
13
[email protected]:~$ cat /tmp/sed.txt
dcba
4321
rekcatSpmeL
[email protected]:~$ sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' /tmp/sed.txt
abcd
1234
LempStacker
[email protected]:~$ sed -r '/\n/!G;[email protected](.)(.*\n)@&\2\[email protected];//D;[email protected]@@' /tmp/sed.txt
abcd
1234
LempStacker
[email protected]:~$

Bibliography

Change Logs

  • 2017.06.15 18:11 Thu Asia/Shanghai
    • 初稿完成