Quit

q [exit-code] , Q [exit-code]

1. 더 이상 명령 사이클을 진행하지 않고 종료합니다.
2. 종료 상태 값을 지정할 수 있습니다.

sed 는 기본적으로 항상 실행 결과 종료 상태 값이 0 입니다. 따라서 grep 명령과 같이 특정 상황에서 오류 종료 상태 값을 반환하려면 quit 명령을 사용할 수 있습니다. qQ 명령의 차이점은 자동 출력 모드일 경우 q 명령은 종료전에 현재 pattern space 의 내용을 출력하고 Q 명령은 출력하지 않습니다. sed 에서 -n 옵션이 사용되면 두 명령은 차이가 없습니다.

$ echo -e "AA\nBB\nCC\nDD\nEE" | sed 'N;N;q3'     # q 
AA                                                # 종료시 patten space 에 있는 
BB                                                # 내용이 출력된다.
CC

$ echo $?
3
---------------------------------------------

$ echo -e "AA\nBB\nCC\nDD\nEE" | sed 'N;N;Q4'     # Q
$
$ echo $?
4
---------------------------------------------

# 입력되는 값 중에 "226 Transfer complete" 문장이 있을 경우 종료 상태 값 0 을 반환하고 종료하고
$ echo "
230 Login successful.
226 Transfer complete.
250 Directory successfully changed.
" | sed '/226 Transfer complete/Q0; $!d; Q1'

$ echo $?
0

# 그렇지 않을 경우는 종료 상태 값 1 을 반환하고 종료
$ echo "
230 Login successful.
XXX Transfer complete.
250 Directory successfully changed.
" | sed '/226 Transfer complete/Q0; $!d; Q1'

$ echo $?
1

sed 는 항상 파일의 처음부터 끝까지 모두 스캔합니다.

sed 는 stream editor 로써 기본적으로 어떤 출력 옵션을 사용하던 상관없이 파일의 처음부터 끝까지를 모두 스캔합니다. 그러므로 처리하는 파일의 사이즈가 클 경우 항상 연산이 완료되는 시점에서 quit 명령을 사용해서 종료해야 합니다.

# 3 번째 라인을 출력하고 스캔이 종료되지 않는다.
$ sed -n '3p' very_big_file
# 파일 스캔이 /END/ 에서 종료되지 않는다.
$ sed -n '/BEGIN/,/END/{ p }' very_big_file

# 그러므로 연산이 완료되면 quit 명령으로 종료해야 합니다.
$ sed -n '3{p;Q}' very_big_file

$ sed -n '/BEGIN/,/END/{ p; /END/Q }' very_big_file

또한 파일 사이즈가 크지 않더라도 다음과 같이 branch loop 를 사용한다면 regex 매칭 영역이 계속해서 증가하므로 처리 속도가 크게 떨어질 수 있습니다. 따라서 매칭 영역이 너무 커지지 않도록 하고 마찬가지로 연산이 완료되면 quit 명령으로 종료해야 합니다.

$ time sed -n '/typedef struct/{ :X N; /ZZZ/!bX; p }' /usr/include/elf.h

real    0m0.328s
user    0m0.327s
sys     0m0.001s

tail 명령과 같이 사용

다음의 경우는 sed 에서 마지막 라인을 출력하는 예인데요. 이와 같은 경우는 그냥 tail 명령을 사용하는 것이 좋습니다. tail 명령은 sed 처럼 파일의 처음부터 끝까지를 모두 스캔하지 않고 바로 파일 포지션을 끝부분으로 이동시키기 때문에 명령이 즉시 실행됩니다.

# 파일의 처음부터 끝까지를 모두 스캔하므로 시간이 오래 걸린다.
$ sed -n '$p' very_big_file

# tail 명령은 즉시 실행된다.
$ tail -n1 very_big_file

# 사이즈가 큰 파일의 뒷부분만 처리하려면 다음과 같이 하는 것이 효율적이다.
$ tail -n100000 very_big_file | sed '...'

Quiz

데이터 파일에서 특정 라인을 추출하는데 제일 빠른 방법은?
약 1G 정도 되는 파일에서 중간 위치의 라인을 추출하는데 tail, head 방법이 제일 빨랐습니다.

# 총 96,603,415 라인의 파일에서 중간 라인을 추출
$ time wc -l file.txt
96603415 file.txt

real    0m0.885s
user    0m0.744s
sys     0m0.140s

$ time tail -n 48301710 file.txt | head -n1
AH3ZM5G9TA

real    0m0.442s
user    0m0.376s
sys     0m0.064s

$ time head -n 48301707 file.txt | tail -n1
AH3ZM5G9TA

real    0m0.627s
user    0m0.708s
sys     0m0.404s

$ time sed -n '48301707{p;Q}' file.txt
AH3ZM5G9TA

real    0m2.402s
user    0m2.336s
sys     0m0.064s