Execute

이것은 sed 가지는 재미있는 기능 중 하나인데요. pattern space 에 있는 내용을 명령문으로 해서 sh -c 형태로 실행을 시킬 수가 있습니다. 그리고 실행 결과가 다시 pattern space 로 저장됩니다. 그러므로 원하는 대로 또 결과를 수정해서 사용할 수 있겠죠?

다음은 명령을 실행했을 때 프로세스 상태입니다.

$ echo "2:3" | sed -E 's#([0-9]+):([0-9]+)#AA=$((\1+\2)); sleep $AA; echo $AA#e' 
5

프로세스가 새로 생성되어 실행되므로 반복해서 여러번 실행할 경우 속도가 느려질 수 있습니다.

e 명령이 실행되는 형태를 2가지로 분류해 볼수 있습니다.

1. s/../../e 를 이용하는 방법, 단독으로 e 명령을 실행하는 방법

이 방법들은 현재 pattern space 에 있는 내용을 명령문으로 하여 sh -c 형태로 실행하고 stdout 값이 다시 pattern space 로 저장됩니다. 단독으로 e 명령을 실행할땐 이후에 다른 문자가 오지 못하므로 -e 옵션을 사용해 분리해야 합니다.

# 'echo hello' 가 pattern space 로 들어가고 'e' 명령에 의해 실행된다.
# 실행 결과 stdout 값이 다시 pattern space 로 저장된다.

$ echo "echo hello" | sed -e 'e' -e 's/.*/& execute/'
hello execute

2. pattern space 와 관계없이 e command 형식으로 직접 실행하는 방법

이 실행 방식은 i 명령과 동일합니다. 실행 결과가 patten space 에 영향을 주지 않고, -n 옵션에 상관없이 결과가 프린트됩니다. 명령문으로 사용되는 스트링은 어떤 값도 올수 있기 때문에 -e 옵션을 사용해 분리해야 합니다.

$ echo "hello" |
sed -n  -e 'e echo ------------'  -e 's/.*/& execute/p' -e 'e echo ============'
------------
hello execute
============

예제 1

다음 예제는 숫자가 포함된 데이터 파일을 읽어들여 max 값을 구한 후 출력합니다.
특별히 의미 있는 예제는 아니지만 여러 가지로 활용하는 방법을 보여줍니다.

sed 에서 사용되는 & , \ 문자를 shell 에서 사용하려면 escape 해야 합니다.

# 데이터 파일
$ cat data
43
2
85
12
5
999
7
26

------------------------

$ sed -En '
    1{h;b}      # 처음 숫자일 경우 hold 하고 END 로 분기합니다.
    G           # 현재 pattern space 에 있는 숫자에 hold space 에 있는 숫자를 append 합니다.
    s/\n/ /     # newline 을 space 로 변경하여 shell 에서 사용될 수 있게 합니다.

    s#.*#set &; if [ $1 -gt $2 ]; then echo $1; else echo $2; fi #e

    h           # 연산 결과를 hold 합니다.
    $p          # 마지막 라인일 경우 값을 표시합니다.
' data

999
------------------------

$ sed -En '
    1{h;b}
    G
    s/\n/ /                 # f() 쉘 함수를 만들어 실행
    s#.*#f() { if [ $1 -gt $2 ]; then echo $1; else echo $2; fi ;}; f & #e
    h
    $p
' data

999
------------------------

# comp.sh script 를 만들어 실행
$ cat comp.sh 
#!/bin/sh

if [ "$1" -gt "$2" ]; then
    echo "$1"
else
    echo "$2"
fi
..........................

$ sed -En '
    1{h;b}
    G
    s/\n/ /
    s#.*#./comp.sh &#e     # comp.sh 스크립트를 실행
    h
    $p
' data

999

예제 2

이번에는 각 라인의 합계를 구합니다.

$ shuf -i 1-20 | paste - - - - - 
16      7       12      20      17
2       4       9       3       6
19      1       11      8       13
15      14      10      18      5

$ shuf -i 1-20 | paste - - - - - |
sed -E '
    p
# `s` 명령에 의해 다음과 같은 스트링이 `sh -c` 에 의해 실행됩니다.
# f() { for n; do  r=$((r+n)); done; echo "sum : $r" ;}; f 7   12   1   10   16

    s/^/f() { for n; do  r=$((r+n)); done; echo "sum : $r" ;}; f /e
'
7       12      1       10      16
sum : 46
11      2       18      17      8
sum : 56
13      5       4       3       15
sum : 40
19      6       9       20      14
sum : 68

예제 3

다음은 데이터 파일에 있는 도메인의 ip 주소를 구하여 추가합니다.

$ cat host
001 naver.com KR
002 daum.net KR
003 google.com US

$ sed -En '
    h
    s#.* (.*) .*#dig +short \1 | head -n1#e
    G
    s#(.*)\n(.*) (.*) (.*)#\2 \3 : \1 \4 #
    p
' host

001 naver.com : 202.179.177.22 KR 
002 daum.net : 61.111.62.173 KR 
003 google.com : 216.58.197.142 US