Addresses
Address 는 입력되는 라인들 중에서 원하는 라인을 선택하기 위해 사용하는 방법입니다.
각 라인들은 라인 넘버를 가지고 있으니까 첫 번째로 라인 넘버를 이용하는 방법이 있구요.
두 번째는 regex 매칭을 이용해서도 지정을 할 수가 있습니다.
address 뒤에 !
문자를 붙이면 logical NOT 역할을 합니다.
,
문자를 이용해 두개의 address 를 연결하면 일종의 address range 를 형성할 수도 있습니다.
address 에 해당하는 명령이 복수개 이상일 경우
{ }
명령 그룹을 이용합니다.
Numeric Addresses
다음은 라인 넘버를 이용해 address 를 지정하는 예 입니다.
# 10번 라인만 프린트
$ sed -n '10p'
# 10번 라인만 삭제
$ sed '10d'
# 20번 라인만 foo 를 bar 로 수정
$ sed '20s/foo/bar/'
$ (마지막 라인)
address 에서 사용되는 $
는 마지막 라인을 뜻합니다.
이문자가 /regex/
에서 사용되면 라인의 끝을 나타냅니다.
# 마지막 라인만 프린트
$ seq 10 | sed -n '$p'
10
first ~ step
first 에 계속해서 step 을 더해나간다고 생각하면 됩니다.
# 1, 4, 7, 10, 13, 16 ...
$ seq 10 | sed -n '1 ~ 3p'
1
4
7
10
# 4, 8, 12, 16, 20 ... 주소 0 의 의미는 뒤에도 나옵니다.
$ seq 10 | sed -n '0 ~ 4p'
4
8
# 위와 같은 결과입니다.
$ seq 10 | sed -n '4 ~ 4p'
4
8
$ ip -4 address | cat -n
1 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN ...
2 inet 127.0.0.1/8 scope host lo
3 valid_lft forever preferred_lft forever
4 2: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc ...
5 inet 220.85.92.78/24 brd 220.85.92.255 scope global dynamic ...
6 valid_lft 4903sec preferred_lft 4903sec
7 4: lxdbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state ...
8 inet 10.24.244.1/24 scope global lxdbr0
9 valid_lft forever preferred_lft forever
10 5: br-958737dcc5b0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc ...
11 inet 172.18.0.1/16 brd 172.18.255.255 scope global br-958737dcc5b0
12 valid_lft forever preferred_lft forever
13 6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue ...
14 inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
15 valid_lft forever preferred_lft forever
$ ip -4 address | sed -n '2 ~ 3p'
inet 127.0.0.1/8 scope host lo
inet 220.85.92.78/24 brd 220.85.92.255 scope global dynamic noprefixroute enp0s25
inet 10.24.244.1/24 scope global lxdbr0
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-958737dcc5b0
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
Regex Addresses
regex 를 이용한 address 지정은 /regex/
형식을 사용합니다.
# 라인에 apple 이 포함될 경우만 프린트
$ sed -n '/apple/p'
# 라인이 file[0-9]+ 과 매칭될 경우만 프린트
$ sed -En '/file[0-9]+/p'
# 라인에 apple 이 포함될 경우만 foo 를 bar 로 수정
$ sed '/apple/ s/foo/bar/'
/regex/I
I
옵션을 사용하면 매칭을 할때 대, 소문자를 구분하지 않습니다.
( s
수정 명령에서도 동일하게 사용할 수 있습니다.)
# 대문자 'LL' 과 소문자 'll' 이 매칭 되지 않는다.
$ echo heLLo | sed -n '/hello/p'
$
# 'I' 옵션을 사용하면 대, 소문자 구분 없이 매칭할 수 있다.
$ echo heLLo | sed -n '/hello/Ip'
heLLo
/regex/M
pattern space 에 라인이 여러개 들어있을 경우 multi-line 모드를 사용할 수 있는데 이 부분은 따로 Multiple lines 메뉴에서 다루겠습니다.
/.../
구분자를 다른 문자로 사용하기
regex 패턴에 디렉토리명과 같이 /
문자가 포함될 경우 /.../
문자와 겹치므로
모두 escape 해야하는데요.
이때 다음과 같은 방법을 사용하여 식을 간단히 할 수 있습니다.
# '/' 문자를 모두 escape 해야 되기 때문에 가독성이 떨어진다.
$ sed -n '/\/usr\/local\/bin/p'
# 구분자로 사용할 임의의 문자를 선정한 후 첫번째 문자만 escape 한다.
$ sed -n '\@/usr/local/bin@p'
$ sed -n '\#/usr/local/bin#p'
$ sed -n '\,/usr/local/bin,p'
/^$/ (공백 라인)
sed 에서 공백 라인은 /^$/
로 표현됩니다.
라인의 처음과(^
) 끝($
) 사이에 아무것도 없으니 공백 라인이 되겠죠.
# 공백라인을 모두 제거하고 프린트
$ sed -n '/^$/!p' file
# 공백라인에 space 나 tab 문자가 포함될 경우
$ sed -n '/^[[:blank:]]*$/!p' file
Range Addresses
address range 에 사용되는 address1, address2 는 numeric 과 regex 를 혼합해서 사용할 수 있습니다.
# 10번 부터 20번 라인까지 프린트
$ sed -n '10,20p'
# 'BEGIN' 이 포함되는 라인부터, 'END' 가 포함되는 라인까지 프린트
$ sed -n '/BEGIN/,/END/p'
# 'BEGIN' 이 포함되는 라인부터, 공백 라인까지 프린트
$ sed -n '/BEGIN/,/^$/p'
# 10번 라인부터 'END' 가 포함되는 라인까지 프린트
$ sed -n '10,/END/p'
# 'MIDDLE' 이 포함되는 라인부터 마지막 라인까지 프린트
$ sed -n '/MIDDLE/,$p'
# 2번 부터 4번 라인까지만 [0-9] 를 X 로 치환
$ cat <<\--- | sed '2,4 s/[0-9]/X/g'
11
22
33
44
55
66
---
11
XX
XX
XX
55
66
$ cat <<\--- | sed -n '/[0-9]/,/[0-9]/p'
AA
11
BB
22
CC # 'CC' 가 빠졌고 '33', 'DD' 까지 프린트 됩니다.
--- # 항상 sed 는 stream editor 라는 생각을 가지고 있어야 합니다.
11 $ cat <<\--- | sed -n '/[0-9]/,/[0-9]/p'
BB AA
22 11
BB
22
CC
33
DD
---
11
BB
22
33
DD
address1 , +N
address1 부터 이후 +N 라인 까지에 해당합니다.
# 3 부터 이후 +2 라인 까지 이므로 결과적으로 3,5p 가 됩니다.
$ seq 10 | sed -n '3,+2p'
3
4
5
$ cat <<\--- | sed -n '/MIDDLE/,+2p' $ cat <<\--- | sed '/MIDDLE/,+2d'
111 111
222 222
MIDDLE MIDDLE
333 333
444 444
555 555
--- ---
MIDDLE 111
333 222
444 555
address1 , ~N
~
문자 는 위에 first ~ step
에서도 한번 나왔는데요. 배수를 뜻합니다.
그러니까 address1 부터 숫자 N 의 배수까지라는 의미가 됩니다.
# 6 을 지나는 4 의 배수는 8 이므로 결과적으로 6,8p 가 됩니다.
$ seq 20 | sed -n '6,~4p'
6
7
8
0 , /regex/
address range 는 결과가 프린트될때 최소 2 라인이 표시됩니다.
그래서 만약에 1번 라인이 address2 에 매칭 되었을때 1번 라인만 프린트할 수가 없는데요.
이때 사용할수 있는 방법이 address 0
입니다.
# address range 는 최소 2 라인이 표시된다.
$ seq 10 | sed -n '1,/[0-9]/p'
1
2
# address '0' 을 이용하면 1번 라인만 프린트할수 있다.
$ seq 10 | sed -n '0,/[0-9]/p'
1
Logical NOT
address range 에서는 !
를 각각의 주소에 사용할 수 없습니다.addr1 , addr2 !
의 의미는 addr1 , addr2
를 제외한 나머지 부분이라고 생각하면 됩니다.
# 3번 라인을 제외하고 모두 프린트
$ seq 5 | sed -n '3!p' # sed '3d' 와 같습니다.
1
2
4
5
# 10 ~ 20 라인을 제외하고 모든 라인에서 foo 를 bar 로 수정
$ sed '10,20! s/foo/bar/'
# 3 ~ 8 라인을 제외하고 모두 프린트
$ seq 10 | sed -n '3,8!p'
1
2
9
10
$ echo -e "AA\n11\nBB\n22\nCC" | sed -n '/[0-9]/,/[0-9]/!p'
AA
CC
$ echo -e "AA\n11\nBB\n22\nCC\n33\nDD" | sed -n '/[0-9]/,/[0-9]/!p'
AA
CC
$ echo -e "AA\n11\nBB\n22\nCC\n33\nDD\n44\nFF" | sed -n '/[0-9]/,/[0-9]/!p'
AA
CC
FF
예제 1
<parent>
와</parent>
로 둘러싸인 값만 프린트 합니다.<parent>
와</parent>
로 둘러싸인 값을 제거하고 나머지 부분을 프린트 합니다.<parent>
와</parent>
로 둘러싸인 값에서 "-SNAPSHOT" 을 삭제합니다.
# 데이터 내용
<modelVersion>4.0.0</modelVersion>
<version>5.1.3-SNAPSHOT</version>
<parent>
<artifactId>xxx</artifactId>
<groupId>group</groupId>
<version>5.1.3-SNAPSHOT</version>
</parent>
<artifactId>yyy</artifactId>
<packaging>pom</packaging>
<name>artifact name</name>
-------------------------------------
# 1번 해답
$ sed -n '/<parent>/,/<\/parent>/p'
# 2번 해답
$ sed '/<parent>/,/<\/parent>/d'
$ sed -n '/<parent>/,/<\/parent>/!p'
# 3번 해답
$ sed '/<parent>/,/<\/parent>/ s/-SNAPSHOT//'
예제 2
공백 라인에 의해 레코드가 분리되어 있고 [name]
형식의 헤더를 갖습니다.
이때 [shovel]
헤더를 갖는 레코드에서 enabled = 0
항목을 enabled = 1
로 변경합니다.
# 데이터 내용
[purple]
auth = no
enabled = 0
username =
password =
priority = 0
host = True
[shovel]
group =
manual = False
enabled = 0
username =
--------------------
$ sed '/\[shovel]/,/^$/ { /enabled/ s/0/1/ }' file