1. 程式人生 > 實用技巧 >linux 文字處理 三大劍客之一 ----sed

linux 文字處理 三大劍客之一 ----sed

目錄

sed命令簡介

sed處理時,有2個緩衝區:【pattern space】和【hold space】

sed執行過程:

先讀入一行,去掉尾部換行符,存入【pattern space】,執行編輯命令。

處理完畢,除非加了-n引數,把現在的【pattern space】打印出來,在後邊列印曾去掉的換行符。

把【pattern space】置空。 接著讀下一行,處理下一行。

sed的預設輸出:【pattern space】裡的內容輸出到標準輸出。

sed的常用選項:

  • 【pattern space】裡的內容不輸出到標準輸出:-n

  • 預設只能執行一個指令碼,執行多個指令碼:-e script, --expression=script

    可以有多個-e script

  • 如果要執行的指令碼特別多,可以指定一個指令碼檔案:-f /path/to/sed_scirpt

    指令碼檔案裡,每行一個編輯命令。

  • 支援使用擴充套件的正則表示式,預設是基本正則表示式:-r

  • 直接編輯原檔案:-i

  • 把【pattern space】空間中的內容覆蓋到【hold space】空間:h

  • 把【pattern space】空間中的內容追加到【hold space】空間,然後刪除【pattern space】空間中的內容:H

  • 把【hold space】空間中的內容覆蓋到【pattern space】空間:g

  • 把【hold space】空間中的內容追加到【pattern space】空間,然後刪除【hold space】空間中的內容:G

  • 互換【hold space】【pattern space】裡的內容:x

  • 把匹配到的行的下一行放入【pattern space】,並把匹配到的行刪除掉:n

  • 把匹配到的行的下一行放入【pattern space】,不刪除匹配到的行:N

  • 刪除【pattern space】空間中的行:d

  • 刪除多行模式下【pattern space】裡的所有行。(比如用N了,【pattern space】裡就有多行):D

編輯命令:

如果有多個命令,則用分號分隔。

刪掉【pattern space】裡的內容:d

刪除start.sh的第二行到第六行。

# nl start.sh | sed '2,6d' 
1	#!/bin/sh
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null
在行前插入:-i \text 支援使用\n實現多行插入
# nl start.sh | sed '3i \new line\nother line'

1	#!/bin/sh
2	set -xv
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
new line
other line
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null
在行後插入:-a \text 支援使用\n實現多行插入
# nl start.sh | sed '3i \new line\nother line'

1	#!/bin/sh
2	set -xv
new line
other line
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null
替換行:-c \text 把匹配到的行,替換成text
# nl start.sh | sed '/java/c \#java被修改的'

1	#!/bin/sh
2	set -xv
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
#java被修改的
#java被修改的
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
#java被修改的
#java被修改的
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null

儲存匹配到的行,到指定檔案中:-w ./sedw.txt

把帶Java的行,保持到/tmp/fsnew

# nl start.sh | sed -n '/java/w ./sedw.txt' 

[root@localhost testsed]# ls
sedw.txt  start.sh  testSed.sh  test.txt
[root@localhost testsed]# cat sedw.txt 
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \

在匹配到的行的上一行,加上行號:=

在以java的行的上一行加上行號

# nl start.sh | sed '/java/=' 

[root@localhost testsed]#  nl start.sh | sed '/java/='
     1	#!/bin/sh
     2	set -xv
     3	basepath="$( cd "$(dirname "$0")"&& pwd )"
     4	echo $basepath
5
     5	$(nohup java )
6
     6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
     7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
     8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
     9	 > /dev/null 2>&1 &)
    10	/dev/null 2>&1
11
    11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12
    12	java -Dio.netty.leakDetectionLevel=ADVANCED \
    13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
    14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
    15	com.hitotek.docker.DockerApplication 1000  &)
    16	/dev/null

匹配到的行不執行後面的命令;沒匹配到的行執行後面的命令:!。注意:!處理命令之前。

刪除不以#開頭的行:

# nl start.sh | sed '/^#/!d' /etc/fstab
#
[root@localhost testsed]# nl start.sh | sed '/java/!d'
     5	$(nohup java )
     6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
    11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
    12	java -Dio.netty.leakDetectionLevel=ADVANCED \

查詢替換:s/要替換的/替換成的/替換標記。它的分隔符/可以自己指定,常用的有s@@@,s###

替換標記:

  • 全域性替換:g
  • 將替換成功的結果儲存到檔案:w /path/to/save
  • 顯示替換成功的行:p

練習

1,刪除test檔案中所有以空白字元開頭的行的行首的所有空白字元

#  nl start.sh | sed 's@^[[:space:]]\+@@'

1	#!/bin/sh
2	set -xv
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null

2,刪除包含java的行 和 config 的行

#  nl start.sh | sed -e 's@java@@' -e '/config/d'
     1	#!/bin/sh
     2	set -xv
     3	basepath="$( cd "$(dirname "$0")"&& pwd )"
     4	echo $basepath
     5	$(nohup  )
     6	$(nohup  -Dio.netty.leakDetectionLevel=ADVANCED \
     8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
     9	 > /dev/null 2>&1 &)
    10	/dev/null 2>&1
    12	 -Dio.netty.leakDetectionLevel=ADVANCED \
    14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
    15	com.hitotek.docker.DockerApplication 1000  &)
    16	/dev/null

sed的常用查詢方式

1、不給地址:對全文進行處理

  • nl start.sh |sed 'p'
1	#!/bin/sh
1	#!/bin/sh
2	set -xv
2	set -xv
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
4	echo $basepath
5	$(nohup java )
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null
16	/dev/null

  • nl start.sh |sed -n 'p'
1	#!/bin/sh
2	set -xv
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
9	 > /dev/null 2>&1 &)
10	/dev/null 2>&1
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
15	com.hitotek.docker.DockerApplication 1000  &)
16	/dev/null 

2、單地址

  • #:指定行
nl start.sh |sed -n '1p'  
輸出匹配的第一行
1	#!/bin/sh

  • /pattern/:被此模式所匹配到的每一行
 nl start.sh |sed -n '/java/p'
輸出匹配的java的行
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \

3,地址範圍

  • $:最後一行
nl start.sh |sed -n '$p'
16	/dev/null
  • #,#:起始和結束
nl start.sh |sed -n '3','5p'     或者   nl start.sh |sed -n '3','5'p
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
  • #,+#:起始,和從起始加多少行
nl start.sh |sed -n '3','+5p'     或者   nl start.sh |sed -n '3','+5'p
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
  • #,/pat1/:起始到,pat1匹配到的行
nl start.sh |sed -n '3','/docker/p'     或者   nl start.sh |sed -n '3','/docker/'p

3	basepath="$( cd "$(dirname "$0")"&& pwd )"
4	echo $basepath
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \

  • /pat1/,/pat2/:pat1匹配到的行,到pat2匹配到的行
nl start.sh |sed -n '/nohup/','/ADVANCED/'p     或者   nl start.sh |sed -n '3','/ADVANCED/'p
5	$(nohup java )
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
12	java -Dio.netty.leakDetectionLevel=ADVANCED \

4,步進:a~b

a為初始值 b為 步數

  • 1~2:1,3,5,7,9.。。行(所有奇數行)
nl start.sh |sed -n '1~2'p  

1	#!/bin/sh
3	basepath="$( cd "$(dirname "$0")"&& pwd )"
5	$(nohup java )
7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
9	 > /dev/null 2>&1 &)
11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
15	com.hitotek.docker.DockerApplication 1000  &)

  • 2~2:2,4,6,8,10.。。行(所有偶數行)
nl start.sh |sed -n '2~2'p 
2	set -xv
4	echo $basepath
6	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED \
8	/home/htga/docker/docker/trunk/target/docker/docker.jar com.hitotek.docker.DockerApplication 1000  \
10	/dev/null 2>&1
12	java -Dio.netty.leakDetectionLevel=ADVANCED \
14	/home/htga/docker/docker/trunk/target/docker/docker.jar \
16	/dev/null

sed比較複雜的例子

+ 取出最後一行:

# nl start.sh | sed '$!d'  或  nl start.sh | sed -n '$p'

[root@localhost testsed]# nl start.sh | sed '$!d'
    16	/dev/null
[root@localhost testsed]#  nl start.sh | sed -n '$p'
    16	/dev/null
  • 第一種解釋:
  1. 1-15行不是最後一行 ($ 最後一行 ) 執行到 $ 條件不滿足
  2. !條件不滿足的時候 反而要執行
  3. 執行d (刪除 pattern space 輸出 pattern space時為空)
  4. 16行 執行到 $ 條件滿足
  5. !條件滿足的時候 不執行
  6. 不執行d
  7. 輸出 pattern space 即 16行
  • 第二種的解釋
  1. 1-15行不是最後一行 ($ 最後一行 ) 執行到 $ 條件不滿足
  2. 條件不滿足的時候 不執行p 即 pattern space 有1-15行資料
  3. 16行 執行到 $ 條件滿足
  4. 條件滿足的時候 執行p 輸出 16行資料
  5. -n 引數 不輸出 pattern space 即 16行

顯示奇數行:

# nl start.sh | sed -n 'p;n'   或者 nl start.sh | sed -n '1~2p'
     1	#!/bin/sh
     3	basepath="$( cd "$(dirname "$0")"&& pwd )"
     5	$(nohup java )
     7	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker & -Xms256m -Xmx512m -classpath \
     9	 > /dev/null 2>&1 &)
    11	$(nohup java -Dio.netty.leakDetectionLevel=ADVANCED -Dglobal.config.path=$basepath -Xms256m -Xmx512m -classpath $basepath/docker.jar com.hitotek.docker.DockerApplication 1000 > /dev/null 2>&1 &)
    13	-Dglobal.config.path=/home/htga/docker/docker/trunk/target/docker -Xms256m -Xmx512m -classpath \
    15	com.hitotek.docker.DockerApplication 1000  &)
  1. p: pattern space 這行 複製到 hold space

  2. n:把要操作的行 往下一行 ;

執行流程解釋

讀入第一行 pattern space

執行p 把第一行的資料 直接輸出

執行n 把第二行的【pattern space】資料刪除 讀入第三行的資料到 pattern space

沒有 -n 再次輸出第一行

執行p 把第三行的資料 直接輸出

執行n 把第四行的【pattern space】資料刪除 讀入第五行的資料到 pattern space

沒有 -n 再次輸出第三行

執行p 把第五行的資料 直接輸出

執行n 把第六行的【pattern space】資料刪除 讀入第七行的資料到 pattern space

沒有 -n 再次輸出第五行

………………

執行p 把第十五行的資料 直接輸出

執行n 把第十六行的【pattern space】資料刪除

複雜查詢特定連續幾行:

cat start.sh |
	sed /^#/d |   
	sed -n '/nohup/{
    p;
    /.*&.*/b endPo;
    :a;
    n;
    p;
    /.*&.*/!b a;
    :endPo;
    }' |  
	sed -n '/nohup.*/{
	/\\/!b endPo;p;
	:a;n;
	p;
	/\\/b a;
	:endPo;
	}'
  • -n 只會輸出匹配的行
  • ^特定開頭
  • d 刪除
  • p輸出
  • b 跳躍某個節點
  • :a 指定a 節點
  • n 讀下一行,並刪除當前【pattern space】裡的內容後,再把下一行的內容放入【pattern space】

其他相關例子

 1,顯示偶數行:
 nl start.sh | sed -n 'n;p'
 2,倒置文字:
 nl start.sh | sed '1!G;h;$!d' 
 
 nl start.sh | sed 'G'

graph LR
A["[]矩形"]-->|"-->箭頭"|B("()圓角")
B---|"---連線"|C(("雙(())圓形"))
C>|粗線|D{"{}菱形"}
C-->E>">]為非對稱"]