Tips

sed 명령을 변수에 저장해 실행하기

$ AA="s/^/X/" BB='s/$/Y/'

$ echo 12345 | sed "$AA; $BB"
X12345Y

$ CC="i-------"

$ echo 12345 | sed "$CC; $AA; $BB"            # i, a, c 명령은 
-------; s/^/X/; s/$/Y/
12345

$ echo 12345 | sed -e "$CC" -e "$AA; $BB"     # -e 옵션을 사용해 분리해야 한다.
-------
X12345Y

pattern space 에 라인을 insert, append 하기

i, a 명령은 pattern space 에는 라인이 추가되지 않습니다. pattern space 의 특정 위치에 라인을 insert, append 하려면 다음과 같은 방법을 이용합니다.

# 3 번째 라인 앞에 추가
# ":X $!{N; bX};" 는 전체 라인을 pattern space 로 읽어 들입니다.
$ echo -e "111\n222\n333\n444" | sed -E ':X $!{N; bX}; s/^/XXXXX\n/M3'
111
222
XXXXX
333
444

# 3 번째 라인 뒤에 추가
$ echo -e "111\n222\n333\n444" | sed -E ':X $!{N; bX}; s/$/\nXXXXX/M3'
111
222
333
XXXXX
444

# 처음 라인 앞에 추가
$ echo -e "111\n222\n333" | sed -E ':X $!{N; bX}; s/^/XXXXX\n/'
XXXXX
111
222
333

# 마지막 라인 뒤에 추가
$ echo -e "111\n222\n333" | sed -E ':X $!{N; bX}; s/$/\nXXXXX/'
111
222
333
XXXXX

-i 옵션 사용시 터미널로 출력하기

-i 옵션을 이용해 파일을 수정할 경우 출력이 파일로 저장되기 때문에 터미널에는 아무런 메시지가 표시되지 않는데요. 다음과 같이 하면 필요할 경우 stderr 로 출력할 수 있습니다.

# bar 가 zoo 로 치환될 경우 file 로 결과가 저장되는 동시에 stderr 로도 출력이 된다.
$ sed -i -e '/foo/{ s/bar/zoo/w /dev/stderr' -e '}' file

데이터를 보는 안목을 기르자

다음과 같이 숫자가 섞여있는 라인에서 N 번째 숫자를 추출하려고 합니다.
이와 같은 경우 먼저 숫자가 아닌 문자들을 삭제해버리면 이후에 추출하기가 수월해집니다.

# 세 번째 숫자에 해당하는 13963  추출하기
[ 2014/05/01 10:48:26 | 13963 | DEBUG ] It took 11.16837501525879 seconds to complete

$ sed -E 's#[^0-9./:]# #g' file
  2014/05/01 10:48:26   13963                   11.16837501525879  

$ sed -E 's#[^0-9./:]# #g; s/\s*(\S+\s+){2}(\S+).*/\2/' file
13963

# 또는
$ sed -E 's/([^0-9]*([0-9]+)){7}.*/\2/' file
13963

다음 예는 0 보다 큰 숫자들을 전부 1 로 변경하려고 하는데요.
이때는 각 컬럼 값을 0 보다 큰지 일일이 비교할 필요 없이 regex 를 이용해 해결할 수 있습니다.

# 데이터 내용
        a       b       c
A       5       2       0
B       0       3       4
C       7       3       4
D       2       0       2

# 두 자리 이상의 숫자도 포할될 경우는 's/[0-9]{2,}|[1-9]/1/g' 
$ sed 's/[1-9]/1/g' file
        a       b       c
A       1       1       0
B       0       1       1
C       1       1       1
D       1       0       1

스크립트가 길때 개행하는 방법

스크립트 명령은 -e 옵션으로 구분하여 실행 할 수 있습니다.

$ sed  -e 's/hamster/this is a hamster./' \
       -e 's/parrot/this is a parror./'   \
       -e 's/turtle/this is a turtle./' file

-e 옵션은 명령 단위로 분리해 작성해야 하므로 만약에 s 하나의 명령이 길어질 경우는 위 방법으로는 안되고 다음과 같이 backslash-newline 을 사용해야 합니다.

$ sed -Ez 's#(\s*)<servlet-name>(\s+)cofaxTools(\s+)</servlet-name>#'\
'\1<servlet-class>\2org.cofax.cms.CofaxToolsServlet\3</servlet-class>#' file

$ sed -En '/(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}'\
'([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])/p' <<\@
192.168.0.1
127.0.0.1
123.456.789.101
10.1.2.4
@

192.168.0.1
127.0.0.1
10.1.2.4

sed 보다 다른 명령을 사용하는게 효율적일 경우

특정 스트링을 추출하거나 N 번째 필드를 추출할 때는 sed 보다는 grep, awk 명령을 이용하는 것이 효율적입니다.

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            7.8G     0  7.8G   0% /dev
tmpfs           1.6G  1.7M  1.6G   1% /run
/dev/sda5        28G   13G   14G  49% /
tmpfs           7.8G   67M  7.8G   1% /dev/shm

# "숫자%" 로 구성된 항목을 추출
$ df -h | sed -E 's/([0-9]+%)|./\1/g'
0%
1%
49%
1%

# grep 명령을 이용하는 것이 효율적입니다.
$ df -h | grep -Eo '[0-9]+%'
0%
1%
49%
1%
--------------------------------------------

# 4번째 컬럼 값을 추출
$ df -h | sed -E 's/(\S+\s+){3}(\S+).*/\2/'
Avail
7.8G
1.6G
14G
7.8G

# awk 명령을 이용하는 것이 효율적입니다.
$ df -h | awk '{ print $4 }'
Avail
7.8G
1.6G
14G
7.8G