RSS구독하기:SUBSCRIBE TO RSS FEED
즐겨찾기추가:ADD FAVORITE
글쓰기:POST
관리자:ADMINISTRATOR
'2006/09/08'에 해당되는 글 143
Linux  2006/09/08 23:34
출처 블로그 > 블로거
원본 http://blog.naver.com/wonie777/120001195066

Part 1: 백업 계획

    모든 사용자들은 적어도 한번쯤 백업을 계획한다. 그러나 유감스럽게도, 우리 대부분은 “백업하지 않는” 것이 오히려 습관처럼 되어있다.

Disclaimer:

    이 기사는 단행본, 하우투 문서들, 맨 페이지, 유즈넷 뉴스그룹, 그리고 셀 수 없는 시간을 키보드와 씨름하며 얻은 유용한 정보들을 제공한다. 비록 모든 주제에 대해 통달했다는 것을 뜻하지는 않지만, 초급자가 중급 사용자가 되는 발판이 될 것이다. 모든 예제들은 우리 홈 네트워크로부터 그대로 가져왔으므로 우리가 아는 한 잘 동작한다.

이 가이드를 어떻게 사용할까

    ·[Enter]처럼 각 괄호에 담긴 단어들은 키보드에서 그 키를 누르거나 마우스 1번 버튼을 누르라는 뜻이다.

    ·{your name here}처럼 구불구불한 괄호 안에 담긴 단어들은 사용자가 입력해야 할 “진짜” 데이터에 대응하는 데이터를 뜻한다.

    ·이탤릭체로(기울어진) 쓰여진 텍스트는 사용자 자신이 셸 프롬프트에 써넣어야 할 명령을 뜻한다.

    필요한 것 들 ( Prerequisites)

    당신의 시스템에 리눅스가 설치되었다면, 필요한 모든 것이 이미 갖추어져 있을 것이다.

    백업 계획  (Backup Plan)

    당신이 홈 네트워크에서 백업을 계획하고 있다면, 몇 가지 작업순서를 정할 필요가 있다. 하드디스크가 전혀 못쓰게 되더라도(crash), 백업의 진정한 가치는 실수로 지운 파일이나 변경된 파일 모두를 반드시 되살리는 것이다. 언제고 당신은 (아마 그리 오래지 않아) 어떤 중요한 파일들을 지우거나 변경할 것이다. 그리고 백업도 없이 부트마저 불가능하게 만들게 될 것이다. 사실 이런 것을 털어놓기는 부끄럽지만, 나는 실제로 /root 디렉터리를 한 방에 날려버렸었다.
     

    譯註: 백업
    대체로 백업의 가치를 절실하게 느낄 때는 이미 돌이킬 수 없는 큰 대가를 치른 뒤일 경우가 많다. 우습게도, 백업에 대한 이 글을 나는 두 번째 쓰고 있다. 새로 구성한 시스템에 백업에 대한 장치를 미처 못하고 있었는데 마침 원본이 손상되어 버렸기 때문이다.

    Note▶ 당신의 시스템이 크랙된 적이 있다면 백업은 깊이 생각한 후에 결정해야 한다. 백업은 수행과정을 매우 단순하게 하거나 녀석들이 시스템을 망치지 못하도록 계획되어야 한다.(특히 홈 네트워크에서는)
    홈 네트워크를 위한 백업계획은 다음 두 가지 영역에 걸쳐 다루어진다: 얼마나 많이 백업을 하려는가? 그리고 어떻게 최소한의 수고로 백업을 할 것인가?

    얼마나 백업을 할 것인가

    백업하는 공간은 바로 돈이므로 나는 모든 백업을 최소한으로 유지하려 애쓴다. 그래서 나는 단지 선택된 디렉터리만 백업할 뿐, 전체 파일 시스템은 백업하지 않는다. /usr와 /opt 등 디렉터리는 인스톨 시디롬에 그 대부분이 들어있으므로, 하드 드라이브가 손상되더라도 기본적인 것들은 그저 다시 설치하면 그만이다. 그러나, 시스템 환경이나 사용자 설정값이 들어있는 /etc나 /home 디렉터리는 어디에서도 복구할 수 없으므로 정말 중요하다.
    백업작업의 효율성과 경제성을 높이기 위해, 당신은 백업 계획에, 선택된 디렉터리를 가끔씩(월 또는 주 단위) 전체 백업을 수행하고, 그 다음엔 변경된 파일만 매일 백업(증분 백업 incremental backups)하도록 설정해야 한다.
     

    譯註: 증분(增分) 백업
    적당한 말을 찾으려 애썼는데 결국 이해하기 어려운 말이 되어버렸다. incremental backups는 증분 백업, 또는 부가(附加)적인 백업이라고 번역되기도 하는데, 전체 백업 후에, 백업 시스템의 효율성을 높이기 위해 변경된 파일들만 대상으로 백업을 추가하는 것을 뜻한다.

    어떻게 백업하는가

    테이프 드라이버는 홈 네트워크 백업용으로 사용하기에는 대체로 너무 비싸고, 플로피 디스크는 실용성이 없다. (나는 백업 디스크 수가 132 장을 넘었을 때 플로피 디스크를 포기해버렸다) 우리는 여분의 하드 드라이브를 사용하는 방법이 가장 좋은 해결책이라고 생각한다. 단, 여기서 말하는 하드 드라이브가 파티션이 아니라는 것에 주의한다! 내 하드 드라이브에 문제가 생긴 모든 경우에 드라이브 전체가 죽거나 못쓰게 되었지, 피해가 하나의 파티션에 끝나지 않았다.
    하드 드라이브를 사용하는 방법이 비록 가장 안전한 방법은 아니지만(譯註: 온라인으로 침투한 크래커에게 시스템이 점령당했을 때 테이프 드라이버가 아마 상대적으로 안전할 것이다), 얼마나 많이 백업할 것인지 범위를 한정하는 방법도 있다.(하지만, 이미 크래커가 은밀히 활동하고 있다면!)
     

    譯註: 백업 파티션과 드라이브
    하드 드라이브에 백업하려면 반드시 원본이 들어있는 하드디스크와 물리적으로 다른 파티션에 설치해야 한다. 나는 하드디스크 하나에 파티션을 몇 개 만들고 그 가운데 하나에 백업파일들을 보존하고 있었다. 루트 파티션에 문제가 생겼을 때 몇 번 백업파티션의 데이터로 복원할 수 있었고, 그래서 나는 꽤 안심하고 있었지만, 하드디스크 스핀들 모터가 고장나자 백업파티션은 아무 소용도 없었다.

    백업 프로그램들

    모든 un*x 계열의 배포판에는 백업에 사용할 수 있는 세 개의 일반적인 프로그램이 포함되어 있다: tar, cpio, 그리고 dump가 그 것으로 각각의 유틸리티는 저마다 장점과 단점을 가지고 있다.

    TAR:
    tar(Tape ARchive)는 소규모 네트워크에서 백업 프로그램으로 가장 일반적으로 사용되는 유틸리티이다. 이 유틸리티는 오래 전부터 여러 가지 용도로 사용되어 왔고, 앞으로도 아마 꽤 오랫동안 남아있을 것이다.
    대부분의 사람이 모르고 있지만, tar는 테이프에 파일들을 옮겨 넣기 위해서 만들어진 것으로 백업용으로 설계된 것이 아니다. tar의 목적은 백업이 아니라 다른 컴퓨터들에서도 설치될 수 있도록 파일들을 테이프에 옮겨 쓰는 것이다. 그런 이유로 tar는 증분 백업기능이 미약하다.

    CPIO:
    cpio는 증분 백업 기능을 제외하고 tar와 비슷한 유틸리티이다. 사실, cpio는 “파일 리스트” 기능조차 없다: 백업본에 포함할 파일들을 선택하려면, cpio는 find 프로그램으로부터 파일이름을 파이핑하여 사용해야만 한다.
    하지만 cpio는 tar에 비해 두 가지 장점을 가진다: cpio는 더 작은 비압축 백업본을 만들고, 백업본에 손상된 부분이 있더라도 프로그램이 그냥 죽어버리지 않는다.
     

    譯註: cpio
    아래는 find 명령의 출력을 cpio의 표준입력으로 사용하는 일반적인 방법이다. /home 디렉터리 아래 모든 파일을 테이프 드라이브(/dev/st0)로 백업한다:

      $ find /home -print | cpio -o > /dev/st0

    find 유틸리티의 -mtime, -newer 등 옵션을 사용하면 증분 백업도 쉽게 할 수 있다. -newer 옵션으로 비교하는 /backup/time/home_full 파일은 최근 백업시간을 기록한 파일이다:
    $ find /home -mtime -l -name .bak -print | cpio -o > /dev/st0
    $ find /home -newer /backup/time/home_full -print | cpio -o > /dev/st0

    cpio와 tar는 압축을 하지 않고, 많은 파일을 묶어 하나의 덩어리로 만드는 유틸리티이다. ‘더 작은 비압축본’은 cpio가 더 효율적으로 파일을 묶을 수 있다는 것을 뜻한다.(일반적으로 백업 대상 파일의 전체크기가 백업매체의 크기보다 훨씬 크다면 tar가 더 유리하다.)

    ‘그냥 죽어버리지 않는다’는 말은 백업본에 손상된 부분이 있다면 그 부분을 건너뛰고 계속해서 작업을 수행한다는 뜻이다. 이 기능이 정말 고마울 때가 있을 것이다.

    DUMP:
    dump는 tar나 cpio와 완전히 다른 프로그램이다. 이 유틸리티는 파일들이 아닌, 파일시스템 전체를 백업한다. dump는 파일 시스템이 하드 드라이브에 있거나, 심지어 그 파일시스템 안에 있는 파일이라도 상관하지 않는다.
    dump 유틸리티는 0-9 단계의 증분 백업을 지원하며, 한 파일시스템을 한번에, 신속하게, 그리고 효율적으로 옮겨 쓴다. 하지만, 가상 디렉터리를 다룰 수 없으며, tar나 cpio보다 훨씬 많은 백업공간을 잡아먹는다.

    우리의 백업 방법

    우리는 run-backup이라는 이름을 가진 백업 스크립트를 사용한다. 이 글의 끝인 Part 3에 쓰여진 글을 그대로 하드 드라이브의 적당한 위치로 옮긴 다음, 아래 명령을 수행해 실행할 수 있도록 설정한다:

    chmod 777 run-backup [Enter]

    run-backup
    스크립트에서 어떤 부분을 고쳐야 할까

    이 스크립트는 변수 네 개만 바꾸면 어떤 컴퓨터에서도 실행할 수 있도록 디자인되었다: COMPUTER, DIRECTORIES, BACKUPDIR, 그리고 TIMEDIR. 현재 우리는 리눅스 박스 두 대와 솔라리스 박스 두 대에서 이 스크립트를 실행하고 있다. BACKUPDIR은 우리 머신에 nfs로 마운트 되어 있지만, 컴퓨터에 연결된 다른 어떤 하드 드라이브라도 상관없다.

    스크립트가 하는 일은 무엇인가?

    스크립트가 실행되면, 먼저 오늘이 이 달의 첫 번째 날인지 검사한다. 만약 그렇다면, 스크립트는 DIRECTORIES 변수에 설정된 디렉터리와 파일리스트 전체를 tar로 묶고, 예를 들어 myserver-01Nov.tgz처럼 파일이름에 컴퓨터 이름과 날짜, 그리고 tgz를 붙인 다음, BACKUPDIR 변수에 설정된 디렉터리에 집어넣는다. 백업본의 파일이름들은 각각 서로 다르므로, 당신이 지우지 않는 한 BACKUPDIR 속에 계속 남아있을 것이다.

    그 다음에, 오늘이 만약 이 달의 첫 날은 아니지만 일요일이라면, 스크립트는 DIRECTORIES에 설정된 목록 전체에 대한 백업을 만들고, BACKUPDIR 안에 있는 일요일 파일에 덮어쓴다. 다시 말하면, 백업 디렉터리에는 오직 하나의 일요일 파일만 있어서 매주 일요일마다 이 파일을 덮어쓰는 것이다. 그런 방법으로 하드 드라이브 공간을 쓸데없이 낭비하지 않도록 만들면서도 여전히 한 주 전의 전체 백업은 남아있게 된다.

    스크립트는 또 일요일의 날짜를 TIMEDIR 디렉터리에 넣어둔다. 만약 오늘이 첫 번째 일요일이 아니라면, 스크립트는 전체 백업이 있었던 일요일 이후에 변경된 파일에 대해서만 모두 증분 백업을 만든다. 그런 이유로 일요일이 지나고 매 요일의 백업은 마지막 파일보다 계속 커지게 될 것이다.

    당신은 최근 24시간 이내에 변경된 파일만 증분 백업을 하고 매 요일의 백업은 최소한으로 유지하려고 애쓰겠지만, 혹시 당신의 하드 드라이브가 이번 금요일에 먼 남쪽(?)으로 가버린다면, 당신은 일요일, 월요일, 화요일, 수요일, 그리고 목요일의 백업을 복원해야만 할 것이다. 일요일과 다른 요일들의 백업으로 백업본은 계속 더 많은 파일을 포함하지만, 당신은 단지 일요일과 목요일의 백업만으로 복원해야한다. 아래에 백업 디렉터리의 간단한 보기가 있다:

    root 828717 Oct 1 16:19 myserver-01Oct.tgz
    root 14834 Oct 22 01:45 myserver-Fri.tgz
    root 5568 Oct 18 01:45 myserver-Mon.tgz
    root 14999 Oct 23 01:44 myserver-Sat.tgz
    root 1552152 Oct 24 01:45 myserver-Sun.tgz
    root 5569 Oct 21 01:45 myserver-Thu.tgz
    root 5570 Oct 19 01:45 myserver-Tue.tgz
    root 5569 Oct 20 01:45 myserver-Wed.tgz

    스크립트를 어떻게 실행시킬까?

    우리는 매일 새벽 1시(모두 잠들어 있을 시간)에 cron 작업으로 스크립트를 실행한다. cron에 대한 자세한 도움말은 Part 2에 있다.

    주의: 증분 백업은 일요일에 백업한 시간을 알아야한다. 만약 당신이 주중에 백업 스크립트를 시작했다면, TIMEDIR 디렉터리 안에 시간파일을 만들어야 한다.(echo $NOW > $TIMEDIR/$COMPUTER-full-date #update full backup date) 예문으로 제공되는 스크립트에서 이 파일 이름은: myserver-full-date이고 그 속에는 다음 한 줄이 들어있다:

    26-Sep

    복원  Restoring:

    복원은 백업보다 상대적으로 쉬운데, 한 가지만 잘 기억하자: tar는 파일이름 앞에 / 문자를 포함하지 않는다. 그러므로 /etc/passwd 파일을 복원한다면 먼저 / 디렉터리로 옮겨간 다음에 아래처럼 명령을 써야한다:

    tar -zxvf {wherever_file_is}/myserver-Sun.tgz etc/passwd
     

    譯註: cpio, dump 복원
    cpio로 만들어진 백업도 일부분을(또는 전체) 복원할 수 있다. 아래는 테이프 백업장치로부터 /etc 디렉터리를 복원하는 명령이다. -m 옵션은 파일 속성을 그대로 복원하며, -d 옵션은 서브디렉터리 구조도 복원하는 옵션이다:

    cpio -imd ‘/etc’ < /dev/st0

    dump로 만들어진 백업은 restore로 복원한다. dump처럼 restore도 사용자에게 상세한 설명을 제공하며, 대화형으로 동작한다.

    다음 달에는 dhcp를 살펴보기로 한다.

    Copyright 1999, JC Pollman and Bill Mote
    Published in Issue 47 of Linux Gazette, November 1999
    &
    http://www.linuxlab.co.kr/~el/

Part 2: Cron

    리눅스 배포판에는 작업일정 관리와 관련된 프로그램으로 두 가지가 따라 나온다: cron과 at가 그 것으로, 둘 다 시스템이 부트될 때 데몬으로 실행된다 - 그래서 이들 프로그램은 결코 끝나지 않는다(시스템이 종료되거나 데몬을 죽이기 전까지). cron 스케줄은 일정을 반복해서 수행하고  at은 한번만 수행한다.

    cron은 crontab 파일로부터 실행에 필요한 정보를 읽어들인다. 시스템과 각각의 사용자는 자신의 crontab 파일을 가진다. 시스템의 crontab은 /etc/crontab에 있다. 이 파일은 그대로 둔다. run-backup 일정을 설정하기 위해, root 사용자로 자신의 crontab 파일을 만들어야 한다.

    루트의 crontab 파일을 만들자

    먼저 EDITOR 변수를 정의한다. 이 변수는 아마 로그인하는 모든 사용자들이 반드시 읽어들이는 /etc/profile 에 넣어두는 방법이 가장 좋을 것이다. /etc/profile을 열고 아래 두 줄을 추가한다.

    EDITOR=vi [Enter]
    export EDITOR [Enter]

    만약 vi보다 더 좋아하는 에디터가 있다면, 당신이 좋아하는 것으로 바꾸길 바란다. 바뀐 변수가 시스템에 반영되려면 로그아웃한 다음 다시 로그인해야한다. 그 다음 아래처럼 쓴다:

    crontab /etc/crontab [Enter]

    이 명령은 시스템의 crontab을 복사하여, 당신이 사용할 crontab 파일을 만든다. 이제, 아래 명령으로 당신의 crontab 파일을 편집한다:

    crontab -e [Enter]

    crontab은 실행되는 프로그램과 설정파일 모두에 사용되는 이름이라는 것을 기억한다 - passwd랑 비슷하다. 아마 아래와 비슷한 줄들이 보일 것이다(原註: 이 예문은 RedHat 배포판의 crontab이다):

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    HOME=/

    # run-parts
    01 * * * * root run-parts /etc/cron.hourly
    02 4 * * * root run-parts /etc/cron.daily
    22 4 * * 0 root run-parts /etc/cron.weekly
    42 4 1 * * root run-parts /etc/cron.monthly

    우리가 실행하려는 명령들이 아니므로 HOME=/ 줄 아래 모든 것을 지우고, run-backup 스크립트가 저장되어 있는 디렉터리 이름을 PATH에 추가한다.

    crontab 안에서 각각의 줄은 프로그램 하나씩을 실행한다. crontab 파일은 특별한 형식을 가지는데: 프로그램이 실행되는 데 필요한 다섯 개의 필드로 구성된다.

    주의: 시스템 crontab 안에는 프로그램을 실행하기 위해 cron 데몬에게 알려주어야 하는 특별한 사용자(예를 들어 root)가 설정되어 있지만, 사용자 crontab에는 이 필드가 필요 없다. 다섯 개의 필드는 다음과 같다:

    minutes hours day-of-month month day-of-week

    맨 페이지에 따르면:

    시간과 날짜 필드는:
     

      field   allowed values
      minute   0-59
      hour    0-23
      day of month    1-31
      month   1-12 (or names, see below)
      day of week     0-7 (0 or 7 is Sun, or use names)

    어떤 필드에 애스터리스크(*, asterisk)가 있다면, “처음부터-끝까지” 항상 설정되어 있다는 의미이다.

    숫자로 된 범위는 허용된다. 하이픈(-, hyphen)으로 두 숫자를 구분하여 범위를 설정하며 앞에 있는 숫자가 뒤보다 작아야한다. 특정 범위는 그 사이 숫자들을 포함한다. 예를 들어, 시간 필드에 사용된 8-11은 8, 9, 10 그리고 11시에 정해진 항목을 실행한다.

    목록은 허용된다. 목록은 숫자들(또는 범위들)을 쉼표(,)로 구분하여 설정한다. 예를 들어: “1,2,5,9”, “0-4,8-13”.

    간격 수치(step values)는 범위에 덧붙여 사용할 수 있다. 범위 뒤에
    “/<number>”를 덧붙여 지정한 범위 안에서 특정 수치를 건너뛴다.
    예를 들자면, “0-23/2”는 한 시간 건너 다른 한 시간마다 특정한 명령을 실행하기 위해 시간 필드에 사용될 수 있다.(V7 표준에서 “0,2,4,6,8,10,12,14,16,18,20,22”이 선택된다.) 간격은 애스터리스크 뒤에도 허용되므로, 당신이 “매 두 시간마다”를 말하려 한다면 그저 “*/2”라고 사용한다.

    “month”와 “day of week” 필드에는 이름이 사용될 수도 있다. 특정한 요일이나 달을 구분할 수 있도록 앞에서 세 글자 정도를 사용한다(문제가 없는 경우). 범위나 목록에는 이름이 허용되지 않는다.

    날짜와 요일이 함께 설정되어 있다면, 두 설정 모두 적용된다. 예를 들어 “30 4 1,15 * 5”라고 다섯 개의 필드가 설정되었다면 매달 1일과 15일, 4시 30분에 명령을 실행하고, 또 매주 금요일마다 같은 명령을 실행한다.

    이제, 우리가 매일 새벽 한 시 5분이 되면 백업 스크립트를 실행하려 한다면, 우리 crontab 파일은 다음과 같을 것이다:

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
    MAILTO=root
    HOME=/

    5 1 * * * /usr/local/bin/run-backup

    그리고 스크립트는 무슨 일이 있었는지 알리기 위해 작업이 끝난 후에는 root에게 email을 보낸다. run-backup 스크립트가 만족할만하게 작동해서 굳이 메일을 확인할 필요가 없다거나, crond로부터 자꾸 날아드는 email이 귀찮아졌다면 MAILTO 줄을 다음과 같이 고친다:

    MAILTO=””

    더 많은 정보를 원한다면, 맨 페이지를 살펴본다:

    man crontab
    (/usr/bin/crontab, 실행파일에 대한 도움)
    man 5 crontab
    (/etc/crontab, 설정파일에 대한 도움)
    man cron
    (cron과 cron 데몬에 대한 도움)

Part 3: run-backup 스크립트

    #!/bin/sh
    # 전체와 증분 백업 스크립트
    # full and incr backup script
    # created 27 Sep 99
    # Based on a script by Daniel O’Callaghan <danny@freebsd.org>

    # 아래 변수 다섯 개를 당신의 컴퓨터/백업에 알맞은 것으로 바꾼다.

    COMPUTER=myserver # 컴퓨터 이름
    DIRECTORIES=”/etc /home” # 백업할 대상 디렉터리
    BACKUPDIR=/backup/backups # 백업본이 만들어질 디렉터리
    TIMEDIR=/backup/backups/last-full # 전체 백업한 날짜를 저장할 디렉터리
    TAR=/bin/tar # tar 유틸리티 이름과 위치

    # 이 아래 줄은 모두 손대지 말고 그대로 둔다.

    PATH=/usr/local/bin:/usr/bin:/bin
    DOW=`date +%a` # 요일 이름, 예를 들어 Mon
    DOM=`date +%d` # 월 단위 날짜, 예를 들어 27
    DM=`date +%d%b` # 날짜와 달, 예를 들어 27Sep

    # 그 달의 첫 날에 영구적인 전체 백업을 만든다.
    # 매주 일요일마다 전체 백업을 만든다 - 이전에 만든 일요일 백업을 덮어쓴다.
    # 한가한 시간에 증분 백업을 만든다.
    # 각각의 증분 백업은 지난주에 만든,
    # 같은 이름을 가진 증분 백업을 덮어쓴다.
    #
    # 만약 NEWER = “” 이라면, tar는 지정한 디렉터리 안의 모든 파일을 백업한다.

    # 그렇지 않다면 NEWER 날짜보다 새로운 파일들만 백업한다.
    # NEWER는 매주 일요일마다 쓰여진 날짜파일로부터 날짜를 가져온다.

    if [ $DOM = “01” ]; then # 달마다 하는 전체 백업
    NEWER=””
    $TAR $NEWER -z -c -f $BACKUPDIR/$COMPUTER-$DM.tgz $DIRECTORIES
    fi

    if [ $DOW = “Sun” ]; then # 매주 일요일마다 전체 백업
    NEWER=””
    NOW=`date +%d-%b`
    echo $NOW > $TIMEDIR/$COMPUTER-full-date
    # 전체백업 데이터를 업그레이드.
    $TAR $NEWER -z -c -f $BACKUPDIR/$COMPUTER-$DOW.tgz $DIRECTORIES

    else # 증분 백업 - 지난주의 백업을 덮어쓴다.
    # 지난번 전체 백업을 한 날짜를 가져온다.
    NEWER=”--newer `cat $TIMEDIR/$COMPUTER-full-date`”
    $TAR $NEWER -z -c -f $BACKUPDIR/$COMPUTER-$DOW.tgz $DIRECTORIES
    fi

     

    譯註: tar 옵션
    tar는 원래 xvzf처럼 하이픈 없이 옵션을 한 덩어리로 묶어 사용한다. 하지만 유닉스계열의 표준 유틸리티들이 하이픈으로 옵션을 구분하므로 위 예문에서 tar는 표준적인 표기형식을 따르고 있다.


2006/09/08 23:34 2006/09/08 23:34
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > 20대의 끝을 잡고
원본 http://blog.naver.com/javancoffee/40003093131

링크 : http://phpschool.com/bbs2/inc_view.html?id=10453&code=tnt2&start=0&mode=search&field=title&search_name=&operator=and&period=last6month&category_id=&s_que=%BD%BA%B8%B6%C6%BC


스마티(Smarty) 템플릿 사용하기

김영진(cogolda@hanmail.net)
이 튜토리얼은 http://www.zend.com/zend/tut/tutorial-cezar.php에 있는
내용은 제가 번역, 추가, 생략했습니다.
소스 코드가 많아서 번역할 내용은 많지 않네요.
질문이나, 의견은 메일이나 코멘트 이용해 주시고,
관심있으신 자료 있으시면, 정리해서 올리겠습니다.
이 자료는 제가 스마티 쓸 때 도움이 되었던 문서이기도 합니다.

대상 독자

이 기사는 PHP templating같은 새로운 웹 개발기술을 적용하고 싶은 PHP 프로그래머와 HTML 디자이너를
위해 작성되었습니다.

Smarty 개요

이론적인 웹 개발 과정은 다음과 같다.
처음에는 디자이너가 유저 인터페이스를 만들고, 그것을 프로그래머를 위해 HTML 조각으로 쪼갠 다음
프로그래머가 HTML안에 PHP 비즈니스 로직을 구현하는 것이다.

그것은 이론적으로는 좋다. 그러나 실질적으로, 내 경험을 빌리자면, 클라이언트는 디자인이나 비즈니스 로직을 변경을 자주 요구한다. 그런 일이 일어날 때, HTML은 변경되고 프로그래머는 HTML 소스 코드를 수정한다.

이런 상황에서 문제는 프로그래머는 디자이너가 레이아웃과 HTML 파일을 완성할떄까지 기다려야 한다는 것이다. 다른 문제는 만약 메인 디자인이 바뀌면, 프로그래머는 새로운 페이지에 적합하기 위해 변경할 것이다. 이것이 바로 내가 스마티(Smarty)를 추천하는 이유이다. 스마티는 PHP를 위한 템플릿 엔진이다.

여러분은 http://smarty.php.net/ 에서 스마티 템플릿을 다운로드 할수 있다. 설치 과정은 매우 단순하다. 문서를 읽고 지시에 따라라.

그래서 스마티가 무엇인가? 스마티는 PHP 스크립트로 템플릿을 컴파일하는 PHP 클래스의 집합이다. 스마티는 템플릿 언어이고 디자이너와 프로그래머에게 매우 유용한 툴이다.
(한국에서 디자이너에게 스마티를 가르치는 것이 가능할까요?)

디자이너를 위한 스마티

디자이너 HTML 파일로 작업한다. 스마티와 작업하기 위해, 여러분은 템플릿 파일로 작업한다. 이런 파일들은 정적인 컨텐츠로 완성했으나, 스마티는 마크업 태그와 함께 결합된다.
(여기서 정적인 컨텐츠라는건 php 코드가 없는 html파일을 애기하는 것입니다.
마크업 태그는 페이지 기술 언어 다시말해 html, sgml, xml이런 걸 애기하는 것입니다.)
모든 템플릿 파일은 확장자가 .tpl이다. 스마티 템플릿 태그는 { and } 구획문자로 감싸진다.

웹 페이지의 기본적인 구조를 생각해 보자. 헤더가 있고, 중간 부분이 있고, 꼬리말(footer)이 있다. 헤더와 꼬리말을 포함하는 파일템플릿 파일 다음과 같다.

{include file="header.tpl"}
<form name="form1">
   Label1 <input type="text" name="text1">
   <input type="submit" value="submit">
</form>
{include file="footer.tpl"}

모든 템플릿은 한 템플릿 디렉토리안에 있어야 한다. 처음에 템플릿을 호출하고 나서, 컴파일된 템플릿은 template_c에 있을 것이다.

스마티 언어는 매우 강력하다. PHP에 모든 변수는 {$Variable_Name}으로 스마티에서 식별된다. 주의할 점은 $ 표시가 앞에 와야 한다. 만약 우리가 PHP에서 $MyName로 호출되는 변수가 있으면, 그 다음에 스마티에서 그것을 출력하기 위해, 우리는 다음과 같이 작성해야 한다.

<html>
   <body>
       Welcome, {$MyName} <br>
   </body>
</html>

스마티의 힘은 유연성에도 있다. 여러분은 템플릿에 IF와 LOOP 삽입할수 있다. IF 문법은 다음과 같다.

{if <condition> }
       html code
{else}
       html code
{/if}

여러분이 링크가 있는 동적인 메뉴를 가지고 있다고 보자. 여러분이 링크를 클릭하면, 여러분은 특정 페이지에 간다. 그래서 여러분은 PHP에서 정수 변수 $Menu가 있다면, 템플릿은 다음과 같다.

{if ($Menu == 1) }
       Option 1
{else}
       <a href=”option1.php”>Option 1</a>
{/if}
{if ($Menu == 2 ) }
       Option 2
{else}
       <a href=”option2.php”>Option 2</a>
{/if}

반복문을 작성하기 위해, 여러분이 PHP에서 다음과 같은 배열을 얻기를 제안한다.
(여기서 얻는다(get)는 표현은 확장자가 php인 파일에 있는 변수나 배열을
템플릿 파일이 가져와야 하기 때문에 이렇게 표현한 것입니다.)

<table>
<tr  
{section name=user loop=$userID}
{if $smarty.section.user.iteration is odd}
       bgcolor=#efefef
{else}
       bgcolor=#ffffff        
{/if}  
>
   <td>    ID = {$userID[user]}  </td>
   <td> Name = {$name[user]}     </td>
   <td> Address = {$address[user]} </td>
</tr>
   {sectionelse}
<tr>
   <td>
       There is no user.
   </td>
</tr>
</section>
</table>

반복자는 스마티를 위한 내부 카운터이다. 그것은 우리에게 섹션의 현제 반복을 알게 해준다. 필자는 만약 현제 반복 변수가 남는지 아닌지 확인으로 인해 테이블에서 다른 열 색깔을 만들기 위해 내부 변수를 사용한다.(뭔 소리를 하는 건지)

LOOPS에 대안은 단일 연관 배열을 반복하기 위해 사용되는 FOREACH이다.

<foreach from=$users item=current_user>
       Name = {$current_user}
<foreachelse}
       No user available.
</foreach>

SECTION과 FOREACH의 중요한 차이는 SECTION은 특정 변수에서 시작할 수 있고, 반복을 위해 스텝을 설정할수 있다. 그에 반해 FOREACH는 모든 변수에 대해 반복할 수 있다.
(뒤에 예제 나오니까 그거 보시면 이해하실수 있을 것입니다.)

프로그래머를 위한 스마티

프로그래머를 위한 장점은 그들은 HTML과 PHP 코드를 분리할 수 있다는 것이다. 좀더 자세히 말하자면, 만약 디자이너가 페이지의 레이아웃을 바꾸면, 프로그래머는 기능적으로 바뀌지 않았다면, 새로운 레이아웃에 적합하게 하기 위해 코드를 바꿀 필요가 없다. 여러분은 여러분의 파일에서 작업하고 화면에 출력되는 모든 변수를 템플릿에 할당하고, 맥주 마시러 나간다.. 디자이너는 레이아웃을 바꾸고 내부적인 에러를 해결하기 위해, 여러분에게 전화 걸고 싶지 않을 것이다.
(쉽게 설명 하자면, 디자이너가 화면 디자인을 살짝 바꾼다음에 프로그래머에게 좀 고쳐달라고 말하지 않아도 됩니다. 여러분이 하는 일은 비즈니스 로직 구현이니까요)

PHP 파일에서 여러분은 스마티 클래스 require ‘Smarty.class.php’를 포함해야 한다.
그리고 $smarty = new Smarty로 인스턴스를 만들어야 합니다.

템플릿에 변수를 할당하기 위해, 여러분은 다음과 같이 해야 한다.
$smarty->assign(‘UserName’, ‘John Doe’).
모두 끝난 다음 여러분은 템플릿 $smarty->display(‘index.tpl)을 보여주기 위해 메소드를 호출한다.

다음과 같은 소스 코드를 보자 (index.php)


<?php
require 'Smarty.class.php';
$smarty = new Smarty;

$smarty->assign('Username', 'John Doe');
$smarty->display('index.tpl');
?>

이런 템플릿(index.tpl)을 보자.


<html>
<body>
       Welcome {$Username}
</body>
</html>

여러분은 역시 PHP에서 템플릿에 그것을 통과하는 배열을 만들수 있다.


$tmp = array ( 'UID'=> '10',  &'Name' => 'John Doe', 'Address'=>'Home address');
$smarty->assign('info', $tmp);

샘플 스크립트 ( 위의 내용은 추상적으로 설명한거고 밑에 내용이 중요합니다.)

이 스크립트는 로컬 데이터베이스에 접속하고 ‘Products’ 테이블에서 모든 제품을 선택(select)한다. 그 때 템플릿에 모든 변수를 통과한다. 그것은 스크린에 그것을 출력한다.


INDEX.PHP

<?php
// 스마티 클래스 파일 포함
require 'Smarty.class.php';
// 스마티 인스턴스 생성
$smarty = new Smarty;
// 디비 설정, 이부분은 각자에 맞게 고치십시오
$hostname = "localhost";
$dbUser = "sqluser";
$dbPass = "sqlpass";
$dbName = "sqldb";
// 데이터베이스에 접속
$conn = mysql_connect($hostname, $dbUser, $dbPass) or die("Cannot connect to the database");
// 디비 선택
mysql_select_db($dbName);
// 질의문 저장
$sql = "SELECT prodID, info FROM products ORDER BY prodID ASC";
// 테이블에서 모든 제품을 선택하라.
$res = mysql_query($sql);
// results를 배열 변수로 선언
$results = array();
$i=0;
while ($r=mysql_fetch_array($res)) {
           $tmp = array(
               'prodID' => $r['prodID'],
               'info'=> $r['info']
           );
           $results[$i++] = $tmp;
}
// 결과를 템플릿에 넘긴다
$smarty->assign('results', $results);
// 템플릿 파일을 로딩load 한다
$smarty->display('index.tpl');
?>


INDEX.TPL

<html>
<body>
Here's a table with the results: <br>
<table cellpadding=1 cellspacing=0 border=0 width=100%>
{section name=nr loop=$results}
   <tr {if $smarty.section.nr.iteration is odd} bgcolor="#efefef"{/if}>
       <td class=fb width=15%>
           <nobr><a href=&#8221;show-product.php?id={$results[nr].prodID}">Press here</a>

       <td class=fb width=29%><a href="show.php?id={$results[nr].prodID}"
       {popup inarray=$smarty.section.nr.iteration}
       >{$results[nr].info}</a></td>
   </tr>

{sectionelse}
<tr><td align="center"><br><b>no product </b> <br> </td></tr>
{/section}
   
</table>

<br>

Here's a select with the results: <br>
<select name="mys">
   {section name=nr loop=$results}
       <option value="{$results[nr].prodID}">{$results[nr].info}</option>
   {/section}
</select>

</body>
</html>


요약

스마티는 디자이너와 개발자 둘 다 에게 멋진 툴이다. 스마티를 사용하면서, 여러분은 사이트 개발과 관리 시간을 줄일 수 있다. 만약 여러분이 개발자라면, 여러분은 더 이상 HTML 코드로 뒤섞인 PHP code가 필요하지 않다. 비즈니스 로직에만 집중하고 디자이너에게 HTML을 떠나라.

번역자에 관하여..
집에서 놀고 있는 백수..

2006/09/08 23:33 2006/09/08 23:33
이 글에는 트랙백을 보낼 수 없습니다
출처 블로그 > kdnnetwork님의 블로그
원본 http://blog.naver.com/kdnnetwork/140000675195
제 목 : 서버 모니터링 툴의 강자, RRDtool 가이드 (작성중. alpha 버전)
작성자 : 좋은진호(truefeel)
작성일 : 2003.9.22(월)~

그래픽 모니터링 툴인 RRDtool과 그 프론트엔드 툴 HotSaNIC의 설치, 운영가이드이다.

1. RRDtool의 이해
2. RRDtool 설치
3. HotSaNIC 설치
4. RRDtool 직접 다루기
5. 문제 해결
6. 이용 사례



1. RRDtool의 이해

RRDtool에 대해 들어가기 전에 먼저 MRTG 툴을 설명할 필요가 있을 듯 하다.
MRTG(Multi Router Traffic Grapher)는 이름에서도 드러난대로, SNMP 프로토콜을 사용하여
라우터를 거쳐가는 트래픽을 실시간 그래픽을 통해 모니터링하는데 가장 많이 사용한다.
이외에 시스템을 모니터링하는 여러 addon들이 있다.
DISK 사용량, CPU사용량, 메모리 사용량, 데몬, 세션 개수 등..
심지어는 P2P인 당나귀의 트래픽, 프락시 서버인 Squid 트래픽까지 실시간(실시간이라기
보다는 특정 시간간격으로 변화하여 보여준다는게 더 정확하지만)으로 웹에서 볼 수 있다.

RRDtool은 MRTG처럼 실시간 그래픽 모니터링 기능을 가지고 있으면서 보다 더 개선된 형태의
툴이다. 보다 빠르고 시스템 로드를 덜 잡아먹는다. 또한 MRTG의 제약이었던 2개 이상의 데이터를
하나의 그래픽을 통해 표시할 수 있다. 그래픽의 유연성(?)면에서도 단연 RRDtool이 압도한다.

[ MRTG로 트래픽 모니터링하는 화면 ]


[ RRDtool과 HotSaNIC으로 CPU 사용률을 모니터링하는 화면 ]


2. RRDtool 설치

RRDtool :
http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/

RRDtool의 시스템 요구사항은 다음과 같다.

Perl 5.005 (컴파일시에 문제가 발생하면 더 최신 것을 설치해본다.)
GNU make
GNU gcc

위 RRDtool 사이트에서 최신 버전을 받아온다. /usr/local/rrdtool에 하는 것으로 가정한다.


# tar xvfz rrdtool-1.0.45.tar.gz
# cd rrdtool-1.0.45
# ./configure --prefix=/usr/local/rrdtool
# make install
# make site-perl-install
... 중략 ...
Installing /usr/lib/perl5/site_perl/5.8.0/RRDp.pm
Installing /usr/share/man/man3/RRDp.3pm
... 생략 ...


3. HotSaNIC 설치

HotSaNIC :
http://hotsanic.sourceforge.net/archive/

HotSaNIC은 RRDtool을 사용하는 툴로 시스템 통계정보를 그래프로 생성해준다.

* 시스템 요구 사항

- RRDtool
- iptables 또는 ipchains (네트워크 트래픽 통계용으로 쓰기 위함)

위 사이트에서 받은 최신 버전은 컴파일없이 환경설정만으로 바로 사용하므로
/usr/local에서 압축을 푼다.


# cd /usr/local
# tar xvf HotSaNIC-0-5-0-pre3.tgz ( HotSaNIC/ 디렉토리가 생성된다. )
# cd HotSaNIC



1) 제공하는 모듈

HotSaNIC은 어떤 모듈을 통해 시스템 통계를 제공하는지 알아보고,
그 모듈을 사용할 것인지 안할 것인지를 판단해보자.


---------   ----------------------------------------------------------- ---------------
모듈      처리하는 통계 정보                      truefeel의 권장
---------   ----------------------------------------------------------- ---------------
APCUSV    APC UPS의 현황 (apcaccess 툴 사용)             N
         (APC UPS를 사용하지 않고 또한 있더라도 서버와 연결하여

                   모니터링중이 아니라면 N)
APPS     데몬, 응용프로그램별 프로세스 현황                Y
          (프로세스 이름 별도 설정 필요)
DISKIO     각 HDD별(파티션별이 아님) 입출력                   Y
         (별도 설정 필요)
DNET     Distributed.Net관련 RC5, OGR, DES, CSC ???         N
NETWORKS  네트워크 트래픽 (별도 설정 필요)                     Y
PART    파티션별 사용량                                  Y
PING     지정한 서버로 ping time 결과 (ping서버 설정 필요)        ping할 서버가

                                                                                                           있다면
SENSORS CPU, 마더보드 등의 온도, 전압등의 수치              원하는대로
SHOUTCAST 지정한 서버와 포트로의 스트링 현황 (서버, 포트 설정 필요)  N
SYSTEM  시스템의 프로세스 수, CPU 사용률, load, 메모리 사용률, ...      Y
TRAFFIC  네트워크 인터페이스별(eth0, ...) 트래픽                   Y
       (SNMP를 통해 라우터나 다른 서버의 트래픽도 모니터링 가능,
         물론 이 때는 별도 설정 필요)
WORMS  웹로그 파일을 이용한 님다, 코드레드 등의 웜 공격 건수           Y
      (웹로그 경로 설정 필요. 문자열 지정으로 다른 웜 공격도 설정 가능)
--------- ----------------------------------------------------------- ----------------


2) setup.pl로 기본 환경 파일 생성

이제 setup.pl 으로 기본 환경 설정을 해보자.
과정은 길지만 간단하다. 모듈을 보고 Y로 할 것인, N로 할 것인지를 결정한다.
이 설정은 나중에 ./setup.pl으로 변경할 수 있으므로 맘 편하게 진행해라.
(반복되는 내용이라 메시지 중간중간 생략하였다.)


# ./setup.pl
Configuring modules:


Module found: APCUSV
----------------------------------------
Do you want to use this module ? (Y)es / (n)o > n

Module found: APPS
----------------------------------------
Do you want to use this module ? (Y)es / (n)o >
Do you want to show this module's graphs on the webpage ? (Y)es / (n)o >

... 중략 ...

Module found: DISKIO  ... 중략 ...
Module found: DNET   ... 중략 ...
Module found: NETWORKS
----------------------------------------
Do you want to use this module ? (Y)es / (n)o >
Do you want to show this module's graphs on the webpage ? (Y)es / (n)o >

setting up networks ...

Configuring local interfaces.
(i)nternal means an interface pointiong to your local machines (intranet)
(e)xternal means an interface connecten with the internet
(n)one means you don't want to account this interface.

Please answer these:
found: eth0 - (i)nternal, (e)xternal or (n)one ? e

found: lo - (i)nternal, (e)xternal or (n)one ? n

... 중략 ...

Module found: PART   ... 중략 ...
Module found: PING   ... 중략 ...
Module found: SENSORS  ... 중략 ...
Module found: SHOUTCAST ... 중략 ...
Module found: SYSTEM  ... 중략 ...
Module found: TRAFFIC
----------------------------------------
Do you want to use this module ? (Y)es / (n)o >
Do you want to show this module's graphs on the webpage ? (Y)es / (n)o >

setting up traffic ...

Configuring local interfaces. Please answer these:
found: eth0 - (y)es or (n)o ? y

found: lo - (y)es or (n)o ? n


Please check the settings file and adapt it to satisfy your needs.
If you have any interfaces slower than 100 MBit, please change the
corrosponding default values.

... 중략 ...

Module found: WORMS  ... 중략 ...
----------------------------------------
Ok.
Writing main settings ...
 checking for OS-type (current: not configured)
OSTYPE="Linux"
 checking path to "rrdtimer" (current: not configured)
DAEMONDIR="/usr/local/HotSaNIC"
 checking path to "rrdtool" (current: not configured)
the following possibilities have been detected:
0 /usr/bin
1 /usr/local/rrdtool/bin

which one shall i use (0=default ... 1) ? > 1 ( rrdtool이 2군데 설치된 경우이다.)
BINPATH="/usr/local/rrdtool/bin" (RRDtool 실행이 있는 디렉토리)
LOGDIR="$DAEMONDIR/var/log/"   (로그가 저장될 디렉토리)
PIDFILE="$DAEMONDIR/var/rrdtimer.pid"
DIAGRAMLOG="last"
LOGSIZE="200000"
LOGBACKUPS="5"
DEBUGLEVEL="-1"
STIME="120"
SCHEDULE_MIN="100"
SCHEDULE_MAX="200"
RUN="apcusv apps diskio dnet networks part ping sensors shoutcast system traffic worm
s"
WEBDIR="not configured"
WIDTH="600"
HEIGHT="200"
IMAGEFORMAT="gif"
SHOW="apcusv apps diskio dnet networks part ping sensors shoutcast system traffic wor
ms"
ORDER="traffic system part ping dnet sensors"
DTIME="15" (15분 간격으로 이미지를 갱신한다.)
CTIME="24" (24시간 간격으로 통계화면 메인에 표시될 작은 크기의 이미지를 갱신한다.)
 guessing convert method...
 checking for Image::Magick perl module... not found
 checking path to "convert" from ImageMagick (current: not configured)
detected: /usr/bin/convert
is this corrrect? (y)
 checking path to "snmpwalk" (current: not configured)
detected: /usr/bin/snmpwalk
is this corrrect? (y)
SNMPWALK="/usr/bin/snmpwalk"
 checking path to "snmpget" (current: not configured)
detected: /usr/bin/snmpget
is this corrrect? (y)
SNMPGET="/usr/bin/snmpget"
checking path to "snmpbulkwalk" (current: not configured)
detected: /usr/bin/snmpbulkwalk
is this corrrect? (y)
SNMPBULKWALK="/usr/bin/snmpbulkwalk"

--- Main settings generated. ---

Writing start/stop script "rrdgraph" ... Ok.

Now adapt all settings files to satisfy your needs.
They are all linked to the directory /var/settings .


3) 필요한 디렉토리 생성

이제 RRDtool의 웹용 이미지와 html이 저장될 디렉토리와 로그 파일 저장 디렉토리를 생성한다.
디폴트로 로그는 HoSaNIC 홈의 var/log에 생성된다.
(html 홈은 /usr/local/apache/htdocs/ 라고 가정)


# mkdir /usr/local/apache/htdocs/rrdtool
# mkdir var/log


4) 환경 파일의 주요 설정

HoSaNIC 홈/settings가 주 설정 파일이고
HoSaNIC 홈/modules/모듈명/settings는 각 모듈별 설정 파일이다.

주 settings 파일에서 주요 설정을 살펴보자.(반드시 확인할 것에 * 표시해둠)


# BINPATH  = rrdtool 실행 파일이 있는 경로 (*)
BINPATH="/usr/local/rrdtool/bin"

# LOGDIR   = HoSaNIC의 로그 파일 경로
# LOGSIZE  = 로그 파일 크기
# LOGBACKUPS = 지정한 개수만큼 로그는 로데이터션되어 백업된다.
#       로그 파일명은 HotSaNIC.log, HotSaNIC.log.1, ...
LOGDIR="$DAEMONDIR/var/log/"
LOGSIZE="200000"
LOGBACKUPS="5"

# RUN  = 실행할 모듈 목록 (*)
# SHOW = 웹페이지로 표시할 모듈 목록 (*)
# ORDER = 표시할 모듈의 순서를 지정(먼저 쓴 것부터 왼쪽에 표시함)
RUN="apps diskio networks part ping sensors system traffic"
SHOW="apps diskio networks part ping sensors system traffic"
ORDER="traffic system part ping sensors"

# WEBDIR   = 생성된 이미지, html이 저장될 디렉토리 (*)
# IMAGEFORMAT = 이미지 파일 형식 (gif 또는 png)
WEBDIR="/usr/local/apache/htdocs/rrdtool"
IMAGEFORMAT="gif"

# DTIME = 지정한 간격으로 이미지를 생성한다. (단위는 분)
# CTIME = 지정한 간격으로 모니터링 메인화면의 작은 이미지를 생성한다. (단위는 시간)
#     따라서 처음 설치한 후 지정한 시간내에 convert.pl 명령을 하지 않으면 메인화면의
#     이미지는 최소 지정 시간동안 볼 수 없다.
DTIME="15"
CTIME="24"

# CONVERTPATH = ImageMagick 를 사용하여 이미지를 생성한다. convert 경로를 지정한다.
CONVERTPATH="/usr/bin/convert"

# REFRESH = 지정한 초단위로 웹페이지를 리프레쉬해서 보여준다. 기본 300초(5분)
REFRESH="300"



각 모듈별 설정은 해당 디렉토리의 settings을 보면 자세히 설명이 되어 있다.
여기서는 ping, diskio, apps에 대해서만 예를 들어본다.

* ping 모듈 ( HoSaNIC홈/modules/ping/settings )

 192.168.123.15(파일서버)에 대해 ping을 한다면, 다음을 추가하면 된다.


HOST=192.168.123.15,File Server


 설정했는데 ping 이미지가 생성안된다면 '5. 문제해결'에 해결방법을 설명해뒀다.

* diskio 모듈 ( HoSaNIC홈/modules/ping/settings )

/proc/stat 에서 disk_io 라인을 살펴보면 다음과 같이 되어 있다.

disk_io: (2,0):(1,1,2,0,0) (3,0):(306090,39930,942826,266160,5212040)
(3,1):(55015,28746,1435800,26269,909568) (8,0):(50,50,253,0,0)

여기서 (3,0) = hda, (3,1) = hdb, (8,0) = sda를 각각 의미한다.
따라서 hda와 hdb의 disk 입출력을 보려면 다음과 같이 설정한다.


DEV=3_0,hda
DEV=3_1,hdb


* apps 모듈 ( HoSaNIC/modules/apps/settings )


APP=httpd,Apache
APP=sendmail,Sendmail
APP=mysqld,Mysql Server
APP=hanterm,hanterm
APP=xmms,xmms
APP=MozillaFirebird-bin,Mozilla Web Browser


5) 실행

자~ 이제 웹페이지를 생성하고 rrdgraph만 실행하면 모니터링할 수 있다.


# ./makeindex.pl
# ./rrdgraph start



이제 웹브라우저를 띄우고 보면 된다. 아직 이미지도 안나온는데 뭘 보라는 것일까?
최소 15분(settings의 DTIME)이 지내야 모듈내의 큰 이미지들이 생성되고
24시간(CTIME)이 지나면 메인의 작은 이미지가 보일 것이다.
24시간 전이라도 적당한 시기에 ./convert.pl을 실행하면 메인에서도 이미지를 볼 수 있다.

부팅할 때 자동으로 rrdgraph가 실행되록 하려면 어떻게 해야할까?
rrdgraph 스크립트를 /etc/rc.d/init.d 에 복사를 한 후 chkconfig로 서비스를 추가한다.


# cp rrdgraph /etc/rc.d/init.d
# chkconfig -add rrdgraph



4. RRDtool 직접 다루기

HoSaNIC은 이미 정해진 모듈을 통해서 RRDtool을 다루는 것이다.
이제 시스템관리자가 원하는 데이터를 RRDtool로 직접 조작하여 통계용 이미지를 생성하는
방법을 알아본다. 간단히 과정을 정리해보면.

- RRDtool용 자체 DB(일반적으로 .rrd로 지정)를 생성한다.(create) ->
- 데이터를 업데이트하거나 (update) 가져온다.(fetch) ->
- 이미지를 생성한다. (graph)

1) rrdtool 명령 익히기

DB 생성, 이미지 만드는 것은 모두 RRDtool홈/bin/rrdtool 명령을 통해서 한다.


* 형식 : rrdtool [명령] [명령 옵션...]
* 예  : rrdtool create coffeenix_status.rrd DS:....


rrdtool에서 사용 가능한 명령은 무엇이 있을까?


---------- -----------------------------------------------------------------------
명 령   설 명
---------- -----------------------------------------------------------------------
create   새로운 RRD DB를 만든다.
update   DB에 새 데이터를 저장한다.
graph    저장된 DB자료를 이용해서 이미지를 생성한다. (.gif 또는 .png)
dump    RRD DB의 데이터를 XML 포맷으로 뽑아준다.
restore   XML 포맷에서 RRD DB로 저장한다.
fetch    RRD DB에서 데이터를 얻어온다.
tune    RRD DB의 설정을 변경한다.
last    RRD DB의 최종 업데이트 시간을 알려준다.
info    RRD DB의 헤더 정보를 보여준다. (파일명, 최근업데이트일, 설정값...)
rrdresize  RRA 크기를 변경한다. 가능하면 사용하지 말기를
xport    RRD DB의 데이터를 XML 포맷으로 뽑아준다. (출력 포맷 지정)
---------- -----------------------------------------------------------------------


2) 샘플 DB 생성

3) 이미지 만들기

5. 문제 해결

1) HoSaNIC 로그 파일을 보니 Can't locate RRDs.pm in @INC (@INC contains... 오류가 있습니다.

  RRDtool 설치할 때 make site-perl-install 를 하지 않아 RRDs.pm 펄 모듈이
  설치되지 않아서 입니다.
  RRDtool 소스 디렉토리에 가서 make site-perl-install을 하세요.
 
2) makeindex.pl 실행할 때 다음 오류가 발행합니다.
  WEBDIR (path to HotSaNIC's output directory) does not exist.

  시스템 모니터링 결과가 저장될 웹디렉토리를 생성하지 않았다.
  위 글중 '3 - 3) 필요한 디렉토리 생성'을 확인해봐라.

3) 시간이 한참지났는데 ping 이미지가 생성이 안됩니다. 물론 ping설정은 했습니다.
  로그를 보니 Can't locate asm/unistd.ph in @INC (did you run h2ph?).. 가 있습니다.

  펄용 헤더 파일이 없기 때문입니다. 펄 헤더로 변환해주는 h2ph로 해결할 수 있습니다.

  cd /usr/include; h2ph -r -l .

6. 이용 사례

  • http://kornet.hanirc.org/chanstat/
     HanIRC의 채널별 사용자 통계를 보여준다. 5분간격의 데이터를 1시간 단위로 자동 업데이트한다.
     장혜식님의 py-rrdtool을 사용한 페이지
    http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/gallery/

    * 참고 자료
  • RRDtool 매뉴얼
     
    http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/index.html
  • itup님의 RRDtool 튜토리얼, 논문 자료
     
    http://myhome.hanafos.com/~itup/index.html
  • 이은태님의 'RRDTool로 서버의 상황을 파악하자.'
     
    http://kltp.kldp.org/stories.php?story=03/02/13/1717339

  • 2006/09/08 23:32 2006/09/08 23:32
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 불행한 바보
    원본 http://blog.naver.com/deepinheart/20000824189
    원격 로그 서버 만들기 완벽 가이드

    좀 오래된 문서이기는 하나 괜찮은 문서 같아서 올려 봅니다.
    좀 오랫된 문서라서 설치 설명에 사용되는 명령어나 패키지들의 버전이 낮지만 설정하는데에는 크게 문제가 되지 않을 겁니다.
    이문서를 토대로 혹 최신 버전에서 설치를 하시는 분들은 성공기/체험기나 제가 메일을 주시면 해당 성공기를 올려 드리도록 하겠습니다.

    원격 로그 서버 만들기 완벽 가이드
    (Complete Reference Guide to Creating a Remote Log Server)

    번역 : 이국현 (errai@hitel.net)
    영문원문링크:http://www.linuxsecurity.com/feature_stories/remote_logserver-1.html
    한글원문링크:http://www.linuxlab.co.kr/docs/01-01-1.htm

    이 문서는 Eric Hines에 의해 쓰여진 것으로, 원격 로그서버를 만들기 위한 자세한 설명과 설정방법등을 다룰 것이다.

    소개(INTRODUCTOIN)
    우선 본 문서에서 언급하고 있는 유틸리티들의 README 화일들에 대해서 열심히 공부해 볼 것을 권한다. 그리고 문서를 읽다 보면 나오는 단어 중 SERVER는 원격 머신(CLIENTS)들로부터 log를 받도록 설정되어진 컴퓨터이고, CLIENT는 원격 로그 서버(REMOTE LOG SERVER)에게 log를 보내도록 설정 되어진 컴퓨터임을 나타낸다.

    A. 원격 로그 서버란 무엇인가?(WHAT IS A REMOTE LOG SERVER)
    원격 로그서버는 다른 시스템들의 log들을 저장할 하드 드라이브 공간을 제공하도록 미리 설정되어진 시스템일 뿐 그 이상도 이하도 아니다.
    이 시스템은 완벽한 보안으로 차단되어 있어야만 한다. 모든 RPC 데몬들이나 다른 기타 서비스들도 암호화되지 않고서는 절대 접근이 허락되지 않는다. 데이타들은 오직 UDP/Port 514 번을 통해서만 전송이 허락된다.
    로그서버에 대한 자세한 설정 및 설치등에 대해서 하나씩 하나씩 접근해 보기로 하자.
    ([역자주] : UDP port 514번은 syslog가 사용하고 있다)

    B. SYSLOGD
    syslogd의 재 컴파일(Recompiling syslogd)

    여러분 컴퓨터에서 원격으로 로그를 남기는 능력을 작동시키기 위해서 첫번째로 할 일은 syslogd의 재 컴파일이다. 이것은 보안상의 이유로써 syslog.conf 화일이 아닌 다른 화일을 읽도록 하기 위함이다. 자세한 내용은 나중에 다루겠다.

    NOTES : 이 아이디어는 Lance Spitzner가 쓴 "To Build a Honeypot"이란 whitepaper를 통해 얻게 되었다. 보안 공동체를 위해 공헌을 한 Lance에게 감사의 말을 전한다.
    이 뛰어난 아이디어는 침입자가 이 시스템에는 원격 로그를 남기는 기능이 없다고 착각하게 만드는 것이다. 이전에 사용한 /etc/syslog.conf 화일을 남겨놓음으로써 예기치 못한 크래커를 속이는데 도움을 줄 것이다.

    STEP 1 : 새로운 버젼으로 컴파일하기 (COMPILING OUR NEW VERSION)
    우선 여러분의 운영체제에는 기본적으로 syslogd가 설치되어 있을 것이고 소스코드는 함께 들어있지 않을 것이다. 여러분은 우선 RedHat 이나 Joey's FTP site(syslogd의 개발자)를 통해 소스 코드를 다운로드 받아야 한다. 여러분의 배포판에서 소스 코드를 제공하지 않는다면 오픈 소스 정책에 위반되는 것이다. 그러므로 아래의 링크에서 소스를 다운받길 원하지 않는다면 여러분의 OS vender에서 소스코드를 얻기 바란다. 

    SITE 1:ftp://ftp.infodrom.north.de/pub/people/joey/sysklogd/
    혹은
    SITE 2:ftp://ftp.sourceforge.net/pub/mirrors/redhat/redhat/redhat-6.2/SRPMS/SRPMS/sysklogd-1.3.31-16.src.rpm

    만약 RedHat계열의 사용자일 때 rpm-iv-vsysklogd-1.3.31-16.src.rpm 라고 실행한다면 /usr/src/redhat/SOURCES/sysklogd-1.3-31 에 인스톨 될 것이다.

    STEP 2 : 기본 설정 화일 위치 변경하기(CHANGING THE DEFAULT CONFIG FILE LOCATION)
    여기는 재미있는 부분이다. 이것은 침입자가 여러분의 log화일이 local에 저장된다고 생각하게끔 속인다. 우리는 syslogd가 다른 설정 화일을 읽도록 재컴파일을 할 것이다. 기본으로 설정되어있는 옛 화일은 침입자가 원격 로그가 기록되는지 cat 등을 실행해서 /etc/syslog.conf를 들여다 보았을 때 속일 수 있을 것이다. 재컴파일해서 새로운 바이너리를 얻더라도 옛 설정화일은 남겨놓도록 하자.

    기본 설정인 /etc/syslog.conf 를 고친다.

    [ehines@myhost sysklogd-1.3-31]$ cd /usr/src/redhat/SOURCES/sysklogd-1.3-31
    [ehines@myhost sysklogd-1.3-31]$ vi syslogd.c

    syslog.conf 부분을 찾는다.
    #define _PATH_LOGCONF   "/etc/syslog.conf"

    이제 여러분이 원하는데로 설정 값을 고치면 된다. 여러분은 /etc/.sys/CORE.conf 같이 독창적으로 설정하기 바란다.
    새로운 syslogd 바이너리가 생겼다면 이전 것 위에 덮어쓴다.
    (대부분은 /sbin/syslogd)이 부분을 실행하기 전에 옛날 버젼은 백업 해두자. 관리자라면 이미 알고 있겠지만, 그렇죠?  :)

    NOTES : 간단하게 예전 syslogd를 가지고 (-f 설정화일)형식으로 실행하지 않은 이유는, 침입자가 ps 등으로 프로세스 리스트를 볼 경우 뒤에 붙은 옵션들이 다 보여서 설정화일을 무엇으로 바꾸었는지 다 알게 될 것이다.
    그러므로 이와 같은 형식으로 하는게 좋다. 필자는 /etc/syslog.conf 파일을 교묘하게 놔두고, 재컴파일을 통해 설정화일을 바꾸는 것을 추천한다.
    그리고 위치만 변경하고 이름은 그대로 두는 것은 위험하다.
    간단하게 find / -name "syslog.conf" 로 찾아낼 수 있다.

    STEP 3 : 진짜 syslog 설정화일 고치기(MODIFY THE (REAL) SYSLOG CONFIG FILE)
    예를 들어, 다음의 syslog.conf 는 모든 메세지를 원격 호스트로 포워딩 하는 것이다.

    # 간단하게 모든 메세지를 원격 호스트로 포워딩.
    *.*            @hostname

    # 모든 커널 메세지를 원격 호스트로 포워딩.
    kern.*         @hostname

    # 로컬에도 기록하면서 원격으로도 기록을 남김 (실패할 경우 대비)
    kern.crit                    @finlandia
    kern.crit                    /dev/console

    기타등등 여러분이 원하는데로 모든 로그화일을 설정한다.

    C. THE CLIENT ( REMOTE LOG SERVER )
    클라이언트 서버(혹은 모든 원격 로그들을 수용하는 컴퓨터)는 원격 로그를 남기기 위해서 syslogd에 -r 스위치를 줘서 실행시켜야 한다.  그리고 /etc/services화일에 syslog 514/udp 가 적혀져 있어야 한다.

    D. 원격 로그 서버 차단하기(LOCKING DOWN THE REMOTE LOG SERVER)
    모든 로그들을 받아들이는 컴퓨터는 완벽하게 외부와 차단되어 있어야 한다.

    1. 모든 서비스 종료시키기 (Turn off(ALL SERVICES))

    이 컴퓨터는 오직 로그 서버일 뿐이므로 다른 서비스들을 실행시킬 필요가 없다. 다음과 같이 실행한다.

    [root@myhost /etc]# cd /etc
    [root@myhost /etc]# vi inetd.conf

    1) 모든 INETD 서비스 종료시키기 (TURN OFF ALL INETD SERVICES)

    여러분은 이 화일에서 '#' 를 추가시킴으로써 주석으로 처리를 할 것이
    다. 아래의 모든 서비스들을 주석처리하기 바란다.

    a. echo
    b. discard
    c. daytime
    d. chargen
    e. time
    f. ftp
    g. telnet
    h. shell
    i. login
    j. exec
    k. comsat
    l. talk
    m. ntalk
    n. dtalk
    o. pop-2
    p. pop-3
    q. imap
    r. uucp
    s. tftp
    t. bootps
    u. finger
    v. cfinger
    w. systat
    x. netstat
    y. auth
    z. linuxconf
    zz. swat

    2) 모든 RPC 서비스 종료시키기 (DISABLE ALL RPC SERVICES)

    [root@myhost /etc]# cd /etc/rc.d

    디렉토리를 살펴보면 대문자 "S"로 시작하는 화일들이 보일 것이다. 이것은 시스템이 부팅할 때 시작되는 서비스들이다. 여러분은 mv 명령어를 이용해서 소문자 s로 바꿔주면 된다. 예를 들어 mv S11portmap s11portmap 이라고 해주면 부트 타임때 portmapper 를 시작하지 않게 된다.

    아마도 nfslock, apmd, netfs, identd, autofs, portmap, atd, pcmcia 와 isdn, sendmail, gpm, httpd, vmware, xfs,linuxconf, local 같은 서비스들을 꺼주면 될 것이다. rc0.d 에서부터 rc6.d 까지 다 종료시켜 주어야 한다.

    2. 계정 삭제(DISABLE ACCOUNTS)

    [root@myhost /etc]# vi /etc/passwd

    여러분의 패스워드 화일에서 사용하지 않는 계정을 삭제해야 한다. 필자는 /bin/noshell(http://www.
    cerias.purdue.edu/coast/archive/data/categ50.html)라는 툴을 다운받을 것을 제안한다.
    이것은 계정을 추가하거나 삭제할 때 관리자에게 유용한 프로그램이다.

    3. SSH의 설치 (INSTALL SSH)

    telnet을 사용하면 sniffing 당할 위험이 있다. 하지만 우리에겐 GNU 오픈소스 공동체의 산물인 OpenSSH이 있다. 자 이제 OpenSSH를 설치해보자.

    1) OPENSSH 다운로드 받기 (DOWNLOADING OPENSSH)

    여러분의 웹브라우져로 www.openssh.com에 접속한다. 이문서가 쓰여질 때 최신버젼은 version 2.1.1로 SSH1과 SSH2 프로토콜을 둘 다 지원한다. 소스를 다운받고 다음과 같이 한다.

    [root@myhost ]# gzip -d openssh-2.1.1p2.tar.gz
    [root@myhost ]# tar -xvf openssh-2.1.1p2.tar

    모든 사항을 똑같이 할 수는 없을 것이다. 계속 진행하기 전에 INSTALL 화일을 꼭 읽어보기 바란다. 필자는 여러분 각각 시스템이 요구하는 사항까지 이야기 해 줄 수 없다. 이것은 단지 필자의 인스톨을 여러분이 지켜보는 것 일 뿐이다.
    우선 Zlib와 OpenSSL을 인스톨을 해야 한다. 

    Zlib: http://www.freesoftware.com/pub/infozip/zlib/
    OpenSSL 0.9.5a or greater:
    http://www.openssl.org/

    RPM버젼의 OpenSSL은
    http://violet.ibs.com.au/openssh/files/support

    GNUmake가 설치되어 있다면 다음과 같이 하면 설치가 될 것이다.

    [root@myhost ]# ./configure && make && make install

    만약 PAM을 사용한다면 /etc/pam.d/sshd 과 같은 PAM control file도 필요로 할 것이다. 일반적으로는 conrtib/sshd.pam.generic 에 포함하고 있다. 사용하기 전에 여러분의 시스템에 맞게 편집해야 할 것이다. 만약 레
    드햇 리눅스 6.2를 사용한다면 contrib/redhat/sshd.pam 이 더 유용할 것이다.
    필자는 configure 할 때 --without-pam으로 PAM 지원을 끄는 것을 좋아한다. 만약 발견된다면 PAM은 자동적으로 스위치가 켜질 것이다.
    --without-pam 옵션은 대신에 RSA 인증을 사용할 경우에 사용된다.

    [root@myhost ]# tar -xvf zlib.tar
    [root@myhost ]# cd zlib-1.1.3
    [root@myhost zlib-1.1.3]# ./configure && make && make install

    설치도중에러가 발생한다면 미안하지만 README 화일을 읽기 바란다. 필자는 에러가 발생하면 README 화일들에서 error에 관련된 사항을 찾아보곤 한다.

    OpenSSL을 인스톨 하기 위해서는 다음과 같은 것이 필요하다.
        *  Perl 5
        *  an ANSI C compiler
        *  a supported Unix operating system

    [root@myhost ]# tar -xvf openssl-0.9.5a.tar
    [root@myhost ]# ./config && make && make test && make install

    이제 OpenSSH를 설치한다.

    [root@myhost ]# cd openssh-2.1.1p2
    [root@myhost ]# ./configure --without-PAM && make && make install

    성공적으로 OpenSSH를 컴파일 했다면 다음과 같은 메세지를 보게 된다.
    Key generation complete.
    Your identification has been saved in /usr/local/etc/ssh _host_key.
    Your public key has been saved in /usr/local/etc/ssh _host_key.pub.
    The key fingerprint is:
    d5:74:83:d0:3f:c4:b4:d6:c5:39:1d:94:ee:9b:a8:61 root
    @soc1.priv.nuasis.com
    Generating DSA parameter and key.
    Your identification has been saved in /usr/local/etc/ssh
    _host_dsa_key.
    Your public key has been saved in /usr/local/etc/ssh
    _host_dsa_key.pub.
    The key fingerprint is:
    ed:58:65:b9:8b:fe:05:81:c2:8c:06:c9:cb:ac:bb:e6 root
    @soc1.priv.nuasis.com

    2) OPENSSH의 설정 (CONFIGURING OPENSSH)

    기본적으로 설정되어진 것을 사용하더라도 나중에 변경할 때를 대비해서라도 ssh config화일을 봐두자. 설정화일
    은 /usr/local/etc/ssh_config, /usr/local/etc/sshd _config 가 있다.
    설치가 끝난 후에는 host key와 DSA key가 생성될 것이다.

    여러분은 SSH 배포판의 문서를 참조해서 설정을 하기 바란다.

    4. 방화벽 (THE FIREWALL)

    패킷 필터링은 여러분의 시스템에 어떤 취약점이 발견되지 전까지는 필요하지 않을 것이다. syslog port(514/udp)를 필터링 하는 이유는 syslog server가 쓰레기 값을 전송했을 때 멈출 수 없기 때문이다. 그러나 더 중요한 것은 udp값이 쉽게 spoof될 수 있게 때문이다.
    이것은 적어도 여러분이 여러 대의 컴퓨터에서 모든 로그가 하나의 인터페이스로 들어올 때 여러분이 외부로부터 들어오는 모든 것을 안전하게 필터링 하게 해준다.

    아래는 리눅스 머신에서 ipchains를 이용한 쉘 스크립트이다.

    #!/bin/sh

    PATH=/usr/sbin:/sbin:/bin:/usr/sbin

    LOCAL_INTERFACE="192.168.1.1/32"
    # put your real IP address
    LOCAL_NETWORK="192.168.1.0/24"
    # put your  local net IP address/mask here
    SSH_PERMITTED="192.168.1.2/32 192.168.2.3/32"
    # who allowed to ssh
    SYSLOG_PERMITTED="192.168.1.5/32 192.168.5.2/32"
    # who allowed to log syslog messages

    # deny everything
    ipchains -P input DENY
    ipchains -P output DENY
    ipchains -P forward DENY
    ipchains -F

    #permit ssh
    for ipaddr in $SSH_PERMITTED;
    do
    ipchains -A input -p tcp -s $ipaddr -d 0/0 22 -i $LOCAL_INTERFACE -j
    ACCEPT
    done

    # permit outgoing tcp
    ipchains -A output -p tcp -i $LOCAL_INTERFACE -j ACCEPT
    ipchains -A input -p tcp ! -y -i $LOCAL_INTERFACE -j ACCEPT

    # permit syslog
    for ipaddr in $SYSLOG_PERMITTED;
    do
    ipchains -A input -p udp -s $ipaddr -d $LOCAL_INTERFACE 514 -i \
    $LOCAL_INTERFACE -j ACCEPT
    done
    # if you would like to log all the other connection
    #attempts, uncommend these...
    #ipchains -A input -p tcp -i $LOCAL_INTERFACE -l -j DENY
    #ipchains -A input -p udp -i $LOCAL_INTERFACE -l -j DENY
    #ipchains -A input -p icmp -i $LOCAL_INTERFACE -l -j DENY

    만약 IP filter 패키지를 이용한다면 대체로 다음과 같을 것이다.
    # close everything on local interface
    # block in all on le0 from any to any

    # pass secureshell
    pass in on le0 proto tcp from 192.168.1.2/32 to 192.168.1.1/32 port= 22
    pass out on le0 proto tcp from 192.168.1.2/32 to 192.168.1.1/32 port = 22

    # or you can replace these two rules with
    #pass in on le0 proto tcp from 192.168.1.2/32 to
    #192.168.1.1/32 port = 22 keep state
    #pass SYSLOG
    pass in on le0 proto udp from 192.168.1.2/32 to 192.168.1.1/32 port = 514

    5. LOG REPORTING

    아무리 좋은 원격 로그 서버를 만들어놔도 여러분이 직접 모니터링 할 수 없으면 무용지물이다. 필자는 다음과 같은 유틸리티를 추천한다.
      *   Logcheck - www.psionic.com
      *   Swatch - www.swatch.org

    아래는 간단한 쉘 스크립트(Mr. Bill Pennington)이다. 이것은 매 일/시간/분 로그화일들을 지정된 이름과 장소에 보관한다.

    #!/bin/bash
    #Simple script to rotate the log files on a daily basis
    #Bill Pennington 1/19/2000

    #Set the date variable
    date=`date +%m-%d-%Y`

    #Rename the messages file
    mv /var/log/messages /var/log/messages.$date
    #HUP the syslog daemon so it writes to a new file
    killall -HUP syslogd

    #Compress the file
    /bin/gzip /var/log/messages.$date
    #Rename the secure file
    mv /var/log/secure /var/log/secure.$date

    #HUP the syslog daemon so it writes to a new file
    killall -HUP syslogd

    #Compress the file
    /bin/gzip /var/log/secure.$date

    #Rename mail file
    mv /var/log/maillog /var/log/maillog.$date

    #HUP the syslog daemon so it writes to a new file
    killall -HUP syslogd

    #Compress the file
    /bin/gzip /var/log/maillog.$date

    #Then scp them somewhere

    6. 시간 (TIME)

    서버는 언제나 정확한 시간과 날짜를 가지고 있어야 한다.  xntpd를 설치한 후에 "ntpdate timeservername"이란 명령을 하루에 적어도 한번정도 실행시켜 줘야 한다.
    필자는 하루에 두 번 씩 이 작업을 시킨다. 물론 여러분이 가진 모든 서버에 해야 한다.

    7. 다른 SYSLOG 장치 (OTHER SYSLOG DEVICES)

    여기에 syslog가 기록하는 것을 설정할 수 있는 CISCO와 같은 다른 장치들이 있다. 여러분의 네트워크와 서버에서 정확한 값을 얻기 위해서는 syslog에서 기록하는 것을 위해 여러분의 모든 장치를 설정해야 한다.

    Cisco
    모든 Cisco 장치들은 syslog를 지원한다. 아래에 몇 가지 예제가 있지만 직접 여러분의 Cisco 문서를 확인해보기 바란다.

    Routers
        In config mode...

        logging <server ip address or name>
        logging facility <facility> defaults to LOCAL7

    Pix Firewall
        In config mode... logging host <ip address of syslog server>
    logging facility
        <facility> defaults to LOCAL4 logging trap <level> from
        emergencies to debug , be carefull with debug you will get a
    ton of traffic!

    Switches
        In config mode...

        set logging server enable
        set logging server <ip address of log server>
        set logging session enable
        set logging level all 1 default

    Windows NT
    여러분은 NT server로 syslog server로 특정작업을 포워딩 시킬 수 있다.
    이와 관련된 여러 개의 shareware /freeware  패키지가 있다.
    http://www.bhs.com 에서 syslog를 검색해보라.

    E. RESOURCES
       * Swatch - http://www.stanford.edu/~atkins/swatch/
       * OpenSSH - http://www.openssh.com
       * LogCheck - http://www.psionic.com/abacus/logcheck/
       * xntp and list of public NTP servers -
    http://www.eecis.udel.edu/~ntp/
       * Cisco - http://www.cisco.com
       * Windows NT software - http://www.bhs.com
       * Robert Graham's sniffing FAQ (hints to build `receive-only
    device'
          http://www.robertgraham.com/pubs/sniffing-faq.html
       * IP Filter - TCP/IP filtering package:
    http://coombs.anu.edu.au/~avalon/

    F. 역자 주

    개인적으로 판단해서 꼭 필요하지 않다고 하는 내용은 삭제 또는 변경하였습니다. 필자(Eric Hines)가 언급한 번역되지 않은 내용은 원문을 참조하시기 바랍니다. :)

    2006/09/08 23:32 2006/09/08 23:32
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 미소
    원본 http://blog.naver.com/osang1997/40007954085
    보내고 받는 메일의 양 제한하기

    시스템의 제한 설정과  서비스의 안정성은 매우 깊은 연관성을 가지고 있다. 기본적으로 대부분의 서비스는 유저가 사용 가능한 시스템의 자원 제한이 거의 설정되어 있지 않은데, 메일 서비스도 마찬가지이다.
    최근에는 메일의 이용율이 높아지고, 메일의 컨텐츠도 전통적인 텍스트 방식에서 음성,이미지등 각종 동영상이 주종을 이루면서 용량도 점점 커지고 있다. 물론 그만큼 하드웨어나 메일 서버의 소프트웨어적인 성능도 향상되고 있지만  용량이 큰 메일을 주고 받는다면 당연히 시스템의 부하가 올라가기 마련이고 이로 인하여 같은 서버내 다른 서비스에까지 영향을 미치게 된다.  따라서 시스탬에서 보내는 메일 서비스(SMTP)나 받는 메일 서비스(POP3)를 제공하고 있다면 용량이 큰 파일을 주고 받는 것을 적절히 제한할 필요가 있다.

    sendmail 은 로컬의 메일을 외부로 발송하는 SMTP(보내는 메일서버) 기능도 있
    지만 외부에서 서버내 계정으로 전송되는 메일을 받아서 서버에 저장하는 기능
    도 있다. 이때 기본적으로는 보내거나 받는 메일의 양에 대한 제한이 전혀 없
    어 10메가 이상이 넘는 큰 사이즈의 메일이 송 수신 될 경우 서버에 과부하가
    걸릴 수 있으므로 아래와 같이 각각의 설정(보내는 메일과 받는 메일의 양)
    을 적절히 제한하여 설정하는 것이 좋다.

    >> SMTP 서버에서 보내는 양 제한하는 법.

    /etc/mail/sendmail.cf (또는 /etc/sendmail.cf. 이는 sendmail 의 패키징 방
    법에 따라 다르다.) 파일에서 다음과 같이 MaxMessageSize 부분의 주석을 제거
    하고 제한하고자 하는 적절한 값을 입력한다.

    # maximum message size
    O MaxMessageSize=5024000

    위와 같이 설정하였을 경우 현재의 서버를 보내는 메일 서버로 이용시 첨부 파
    일이 5M 이상 초과하거나 웹에서 /usr/sbin/sendmail 을 실행하여 외부로 메일
    을 발송하는 메일링 리스트등의 프로그램에서도 메일 발송시 5 메가 이상의 메
    일은 보낼 수 없게 된다.
    5024000 은 byte 단위이며 설정 변경 후 변경된 내용을 적용하려면 killall –
    HUP sendmail 로 sendmail 데몬을 Refresh 하면 된다.

    >> 받는 메일 서버에서 받는 양 제한하는 법.

    외부에서 서버로 들어오는 메일에 대해서 용량을 제한하고 싶다면 같은 파일
    (sendmail.cf) 에서 "Local and Program Mailer specification" 부분을 설정
    해 주면 된다.

    Mlocal, P=/usr/bin/procmail, F=lsDFMAw5:/|@qSPfhn9, S=10/30,
    R=20/40, M=5024000, T=DNS/RFC822/X-Unix, A=procmail -Y -a $h -d $u

    위와 같이 T=DNS/RFC822/X-Unix  앞부분에 M=5024000 부분을 추가해 주면 된
    다.
    마찬가지로 5024000는 byte 단위이며 각자의 시스템 환경에 따라 원하는 용량
    만큼 적절히 설정해 주면 된다   역시 설정 변경 후 sendmail 을 refresh 하
    면 적용이 된다.
    위의 경우 서버에서는 5메가 이상의 메일은 수신하지 않으며 5메가 이상의 메
    일을
    보낸 이는

    552 5.2.3 <antihong at tt.co.kr>... Message is too
    large; 5024000 bytes max
    554 5.0.0 <antihong at tt.co.kr>... Service
    unavailable
    와 같은 에러 메시지를 회신받게 된다. 

    아울러
    # maximum number of recipients per SMTP envelope
    O MaxRecipientsPerMessage=20

    와 같은 부분이 있는데, 이 부분은 한번에 메일 발송 시 동시 발송(참조 발송)
    이 가능한 메일 계정의 수를 뜻하는 것으로 SMTP 서비스를 제공한다면 이 설정
    을 적용하는 것이 좋다. 기본적으로 이 값에도 제한이 없으므로 먼저 주석을
    삭제한 후 적절한 값을 설정해 주면 한번에 동시 발송 가능한 메일의 수도 제
    한할 수 있다.
    (위의 경우에는 한번에 참조 발송이 가능한 메일 유저를 20명으로 제한)
    설정이 끝난 후에는 killall –HUP sendmail 로 sendmail 을 재가동해주면 적
    용된다.



    메일 용량 쿼터 설정하기

    각 유저의 홈페이지 공간에 대한 쿼터 설정방법은 잘 알고 있는데, Sendmail
    을 제공시 메일 용량 쿼터에 대한 설정은 잘 모르는 경우가 많이 있다. 매일
    쿼터에 대한 설정은 다소 복잡하기는 하지만 설정은 가능하다.  기본적으로
    각 유저의 메일은 /var/spool/mail/ 디렉토리에 자신의 계정 소유로 저장이 되
    게 되는데 바로 이 특성을 이용하여 쿼터 설정이을 하면 된다.   쿼터는 각 파
    일 시스템별로 각각 설정이 가능하므로 각 유저의 홈디렉토리외에 /var 파티션
    에도 추가적으로 쿼터를 설정하면 되는 것이다.
    쿼터를 설정하는 방법은 일반적인 방법과 동일하다.
    먼저 /etc/fstab 파일을  열어 /var 파티션이 별도로 설정되어 있다면 /var 파
    티션에,  별도로 없으면 / 파티션에 유저쿼터나 또는 그룹쿼터 설정을 하면 된
    다.

    /dev/sda1             /home       ext2    defaults,usrquota=/home/.quota
    /dev/sda8             /var         ext2   
    defaults,usrquota=/var/.mailquota

    위에서는 /home 파티션에도 쿼터 설정을 하고 /var 파티션에도 쿼터 설정을
    한 것을 볼 수 있다.  이후 touch /home/.quota 및 touch /var/.mailquota 로
    사이즈가 0인 파일을 생성한 후  quotacheck –a 를 실행하면 파일 시스템을
    스캔하여  디스크 사용량을 체크하여 해당 파일에 정보를 저장한다.

    edquota user 를 실행하면

    /dev/sda1: blocks in use: 0, limits (soft = 99980, hard = 99980)
           inodes in use: 0, limits (soft = 0, hard = 0)
    /dev/sda8: blocks in use: 0, limits (soft = 29980, hard = 29980)
           inodes in use: 0, limits (soft = 0, hard = 0)

    위와 같이 쿼터 설정이 나오는데,  여기에서 /dev/sda1 은 /home/ 디렉토리에
    대한 쿼터 설정이고, /dev/sda8 은 /var/ 디렉토리에 대한 쿼터 설정이다. 위
    설정으로 각각 /home 디렉토리에는 100메가로, 메일 용량은 30메가로 총 130메
    가를 할당하여 쿼터를 설정한 것을 알 수 있다. 만약 별도의 /var 파티션이 없
    이 / 파티션만 있는 상황에서 100 메가로 쿼터 설정을 했다면 이 용량은 홈페
    이지의 용량과 메일 용량을 합쳐서 100메가로 적용이 되므로 주의하기 바란다.

    ##################### 참고.  Quota 의 설정에 대해
    위와 같이 edquota 사용시 관련된 라인이 아래와 같이 보이는 부분이 있다.
    이 중
    "blocks in use:" 는 유저가 현재 파티션에서 사용중인 총 블럭의 수를 킬로
    바이트로,
    "inodes in use:" 는 유저가 현재 파티션에서 사용중인 총 파일의 개수를 보
    여준다.
    이 두개의 "blocks in use:" 와 "inodes in use:" 는 시스템에 의해 자동으
    로 설정되고
    제어되므로 이 값을 임의로 변경할 필요는 없다.
    그리고 quota 설정시 soft 제한(soft = 5000)은 유저가 사용할 수 있는 최대
    용량을 뜻하며  (이 예제에서는 약 5M 이다.) hard 제한(hard = 6000)은 유저
    가 초과할 수 없는  절대적인 디스크 사용량을 뜻한다.  "hard limit"
    는 "grace period" 옵션이 설정되었을 때에만 적용된다.
    grace period 는 쿼터가 설정된 유저나 그룹이 soft limit 을 초과한 이후에
    도 사용 가능한 시간의 한계이다. 예를 들어서 여러분이 관리하는 시스템
    에 "해당 유저의 홈디렉토리를 50MB 로 쿼터 제한하고  초과시 7일간의 유예기
    간을 준다"는 정책을 세울 수도 있다. 각자 유예 기간의 설정에 대해서는 나름
    대로 적당하다고 생각하는 기간을 정의할 수 있다. grace period 는
    edquota –t 로  확인 및 설정할 수 있으며 아래의 경우에는 grace period 가
    7일로 설정되어 있는 것을 알 수 있다.

    /dev/sd1: block grace period: 7 days, file grace period: 7 days
    /dev/sda8: block grace period: 7 days, file grace period: 7 days

    그리고 한 유저에게 적용된 쿼터 설정을 다른 유저에게도 그대로 적용하려
    면 –p 옵션을 사용하면 되는데, 아래와 같이 실행하면 edquota 프로그램
    은 /etc/passwd 에 정의된 유저중 UID 가 499 이후의 모든 유저에 대
    해 "user" 의 쿼터 설정을 그대로 복사하게 된다.

    edquota -p user `awk -F: '$3 > 499 {print $1}' /etc/passwd`

    ####################################################################


    만약 쿼터가 초과된 계정에 메일을 발송하게 되면 아래와 같은 에러 메시지가
    나며 더 이상 메일을 수신하지 못하게 된다.







    sendmail 이 정상적으로 작동하는지 여부를 아는 방법

    sendmail 이  현재 작동중인지 확인하는 방법은 아래 두 가지 방법으로 가능하
    다.

    (1) # ps auxw|grep sendmail 로 확인
    위와 같이 확인시 
    root      0.0  0.0  2684 1460         S    Aug24 sendmail: accepting
    connections on port 25

    와 같이 sendmail: accepting connections on port 25 로 보이면 정상적으로
    작동하는 것이다. 만약 sendmail 이 다운되어 작동하지 않을 때는 sendmail:
    rejecting connections 라는 메시지가 보이게 된다.

    (2) sendmail 이 반응하는 25번 포트로 접속.

    # telnet tt.co.kr 25
    Trying 211.47.66.50...
    Connected to tt.co.kr.
    Escape character is '^]'.
    220 www10.tt.co.kr ESMTP Today and Tomorrow (http://tt.co.kr/)

    와 같이 sendmail 이 바인딩하는 25번 포트로 telnet 을 접속하면 sendmail
    이 반응을 하게 되는데, 위와 같이 접속을 하여 응답이 있을 경우에는 접속을
    받아들일 준비가 되어 있는 상태이며 반응하지 않을 때는
    Trying  tt.co.kr...
    telnet: Unable to connect to remote host: Connection refused
    와 같이 접근이 거부되었다는 것을 알 수 있다.


    갑자기 sendmail 이 작동하지 않을 때

    sendmail 이 작동하지 않는 경우는 주로 2가지이다.

    첫번째는, 시스템의 부하율인 Load Average 가 높아져 sendmail 이 작동하지
    않는 경우이고 두번째는 sendmail 에서 받는 메일이 저장되는 /var 파티션이
    100%가 되었을 경우이다.
    Sendmail 은 기본적으로 시스템의 Load Average 수치가 12를 초과하였을 경우
    에는 자동으로 작동하지 않게 되는데 이는 sendmail이 서비스 거부 공격등으
    로 시스템의 부하가 높아졌을 때 sendmail 로 인하여 시스템이 다운되는 것을
    막기 위한 조처이다.
    이 값을 수정하려면 sendmail.cf의
    # load average at which we refuse connections
    O RefuseLA=12
    에서 수정한 후 killall –HUP sendmail 로 재실행해 주면 되고, 이 값은 각각
    의 시스템에 따라 적절히 조정하면 된다.  만약 현 시스템의 특성상 늘 부하
    가 높아 로드가 자주 12를 초과한다면 이 값을 각자의 시스템 환경에 맞게 적
    절히 조절하여야 외부에서 오는 메일을 받을 수 있게 된다.(서버에서 25번 포
    트로 바인딩하고 있어야 외부에서 오는 메일을 수신할 수 있다.) 그리고 메일
    이 저장되는 /var/spool/mail 파티션이 가득 찼을 경우(파티션 100%) 에도
    sendmail 이 작동하지 않으므로 파티션이 가득 찼을 경우에는 /var/log/ 등에
    서 불필요한 데이터를 삭제하여 /var/spool/mail 이 포함된 파티션이 100% 를
    넘지 않도록 하여야 한다. 용량 정리를 하여 파티션이 100%가 넘지 않으면
    sendmail 이 자동으로 살아나는 것을 알 수 있다.
    또한 시스템의 Load Average 가 8을 넘으면 서버를 통해 메일을 발송해도 메일
    을 통해 바로 전송되지 않고 일단 서버의 메일 큐에 저장이 된 후에 발송이 되
    게 된다. 이 역시 같은 이유 때문인데 이 수치는 sendmail.cf 의

    # load average at which we just queue messages
    O QueueLA=8
    에서 적절히 설정하면 된다.

    참고로 현재 시스템의 Load Average는 w 명령어를 이용하여 확인 가능하다.
    w 를 이용시 시스템의 Load Average 는 0.25, 0.40, 0.43  와 같이 보이는데
    이는 각각 현재를 기준으로 지난 1분, 5분, 15분간의 평균 시스템 부하율을 나
    타낸다.



    sendmail 애서 보내는 메일(SMTP) 기능을 차단하고자 할 때

    sendmail 에서 Relay 기능을 막아 두었다 하더라도 최근 버전에는 사용자 인증
    (SMTP AUTH) 기능이 있어 서버에 계정이 있으면 모든 유저가 메일 서버를 이용
    해 SMTP 기능을 이용하여 메일을 발송할 수 있다. 이를 막으려면 최신의
    8.11.4 나 8.11.5 와 같이 최신 버전으로 업그레이드 후 /etc/mail/smtpauth
    파일에 보내는 메일  기능을 허용할 유저를 입력해 주면 된다. (최근에
    8.11.6 이전 버전에 심각한 보안 문제가 확인되었으므로 반드시 8.11.6 버전이
    나 8.12 버전으로 업그레이드하여야 한다.)  파일을 생성 후 아무런 유저도 입
    력하지 않으면 서버에 계정이 있다 하더라도 어느 누구도 메일을 발송할 수 없
    게 된다. 따라서 최신의 8.11.6 버전으로 업그레이드 할 것을 권장한다. 이외
    여러 변형된 방법이 존재하는데, ipchains 나 iptables 를 이용해 패킷 필터링
    을 하는 방법도 있다.

    커널 2.2.X 일 경우
    ipchains -A output -p tcp -y -d 0/0 25 -j DENY
    커널 2.4.X 일 경우
    iptables -A OUTPUT -p tcp --syn --dport 25 -j DROP

    위와 같이 설정시 목적지(Target) 포트가 25번 포트로 향하는 초기화(SYN) 패
    킷만을 차단하여 메일을 발송할 수 없도록 한다. 물론 초기화(SYN) 패킷에 대
    해서만 필터링을 하였으므로 외부에서 오는 메일을 받는 것은 관계 없다.

    바이러스 메일 필터링 방법

    최근에 Sircam 이나 Nimda 등 일정 주기마다 발생하는 바이러스 메일 때문에
    서버 관리자들은 마음 고생이 이만저만이 아니다. Sendmail 에서는 이러한 바
    이러스 메일이나 스팸메일에 대해 룰셋(ruleset)을 이용하여 차단하는 기능이
    있는데, 이를 사용하는 방법에 대해 알아보도록 하자.
    Sendmail 에서는 제목이나 메일러 또는 첨부파일의 화일명등 각종 메일헤더 정
    보를 이용하여 필터링을 할 수 있는데, 먼저 발송되는 메일 제목(subject)으
    로 필터링을 해 보도록 하자. 아래는 메일 제목에 ILOVEYOU 로 발송하는 멜리
    사 바이러스를 차단하는 룰셋을 적용해 본 예이다.

    먼저 sendmail.cf 파일을 열어 제일 하단에 아래의 내용을 추가한다.

    HSubject: $>Check_Subject
    D{WORMmsg}Access Denied - This message may contain a virus.

    SCheck_Subject
    RILOVEYOU               $#error $: 501 ${WORMmsg}
    RRe: ILOVEYOU           $#error $: 501 ${WORMmsg}
    RFW: ILOVEYOU           $#error $: 501 ${WORMmsg}

    # 주의 :  $#error 앞의 blank는 스페이스가 아니라 반드시 탭으로 띄워주어
    야 한다.
    Sendmail.cf 의 설정 내용이 다소 어렵고 복잡하기는 한데, 위 설정의 의미를
    간단히
    살펴보도록 하자.

    H -- 위 경우에는 헤더에서 Subject:라는 문자열을 찾아 이 헤더를
    Check_Subject로 정의한다.
    D -- WORMmsg 라는 매크로를 정의하여 해당 룰셋에 적용되는 제목을 확인시 발
    송한
       유저에게 보낼 메시지를 정의한다.
    S -- 헤더에서 check_subject로 정의한 부분을 룰셋으로 지정하는 부분이다.
    R -- 해당 문자열이 포함된 메일을 발견시 앞에서 정의한 에러 메세지를 첨부
    하여
        반송을 시킨다.

    위와 같이 룰셋을 적용하였을 경우 "I LOVE YOU" 와 같이 공란이 있을 경우 적
    용되지 않으며 "ILOVEYOU from me" 와 같이 특정 단어가 추가시에도 적용되지
    않으며 반드시
    정확히 일치하여야 한다. 추가적으로 회신시 추가되는 Re: 와 전달(포워딩)시
    추가되는 FW: 가 추가된 메일도 거부한다.

    다음으로 얼마전 유행했던 Sircam 바이러스 메일을 필터링해 보도록 하자.
    Sircam 바이러스의 헤더를 보면 정상적인 메일과는 달리 메일 헤더에
    Content-Disposition: Multipart message 와 같은 부분이 추가되어 있으며 이
    특징을 이용하여 필터링을 하면 된다.

    Sendmail.cf 파일에 아래의 룰셋을 추가하면 된다.

    HContent-Disposition: $>check_sircam
    D{SIRCAM}"Warning: I  Guess Sircam.worm Virus"
    Scheck_sircam
    RMultipart message      $#error $: 550 ${SIRCAM}

    # 주의 :  $#error 앞의 blank는 스페이스가 아니라 탭으로 띄워주어야 한다.

    sendmail.cf의 수정을 끝낸 후 바로 sendmail을 재 시작하지 말고
    룰셋이 정상적으로 작동하고 있는지 아래와 같이 테스트를 하는 것이 좋다.

    # /usr/lib/sendmail –bt                 # 테스트 모드로 접속
    ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
    Enter 
    > check_sircam Multipart message        # Sircam 룰셋 테스트
    check_sircam       input: Multipart message
    check_sircam     returns: $# error $: 550 553 Warning: I  Guess
    Sircam.worm Virus
    > ctrl-D                                # 테스트 종료

    위와 같이 확인된 후 sendmail을 재시작(killall –HUP sendmail) 하면 바로
    적용된다.
    아래와 같이 tail –f  /var/log/maillog 로 로그 파일을 지켜보면 아래와 같
    이 실제로 Sircam 바이러스가  필터링되고 있음을 확인할 수 있다.

    Sep  27 15:09:51 www sendmail[21386]: f8369of21386:
    to=<antihong at tt.co.kr>, delay=00:00:01,
    pri=241584 Warning: I  Guess
    Sircam.worm Virus.

    마지막으로 최근에 가장 영향을 많이 주었던 변형된 Nimda Worm 을 필터링하
    는 방법에 대해 알아보자. Nimda Worm 은 정상적인 메일 메시지와 달리 헤더에
    boundary="====_ABC1234567890DEF_===="       나
    boundary="====_ABC123456j7890DEF_===="      라는 부분이 있는데, 이 부분으
    로 필터링을 할 수 있다. 즉 메일 헤더에 위와 같은 설정이 되어 있으면 
    Nimda Worm 으로 간주하고 필터링 하면 되는 것이다. Sircam 에서와 같은 방법
    으로 sendmail.cf 파일의 설정은 아래와 같다.

    HContent-Type: $>check_ct

    D{NIMDA}"I guess NIMDA.WORM!!!"

    Scheck_ct
    R$+boundary="====_ABC1234567890DEF_===="       $#error $: 550 ${NIMDA}
    R$+boundary="====_ABC123456j7890DEF_===="       $#error $: 550 ${NIMDA}

    이외 메일 필터링에 대한 더욱 구체적인 방법에 대해서는 
    http://certcc.or.kr/paper/tr2001/tr2001-03/email security by
    procmail.html 나
    http://quanta.khu.ac.kr/~dacapo/sendmail/rulesets/ 를 참고하기 바란다.
    그리고 이외 관련하여 바이러스를 스캔하거나 필터링 할 수 있는 몇몇 프로그
    램이 있는데 이에 대해서는 http://www.rav.ro/ , http://www.amavis.org/ ,
    http://www.sophos.com/ 등을 참고하기 바란다.


    메일이 받아지지 않는 경우

    아웃룩 익스프레스에서 “배달” 을 눌러 메일을 수신하려고 할 때 메일이 받
    아지지 않는  경우가 있다. 이러한 경우에는 아래와 같이 여러가지 이유가 있
    을 수 있으니 아래의 사항에 대해 하나씩 원인을 찾아보기 바란다.
    (1) IMAP 패키지가 설치되지 않았을 경우
    서버에 배달되어 있는 자신의 계정으로 온 메일을 클라이언트 PC에서 받으려
    면 pop3 데몬이 반응하게 된다.  pop3d 는 IMAP 패키지안에 포함되어 있으므
    로, IMAP 패키지를 설치하여야 pop3 를 사용할 수 있다. Rpm 으로 설치했다면
    rpm –q imap 으로 현재 시스템에 imap 패키지가 설치되어 있는지 확인한다.
    또는 /usr/sbin/ipop3d 파일이 있는지 확인해 본다.
    (2) Inetd 에 설정되어 있지 않을 경우
    pop3d 는 inetd 또는 Xinetd 에서 작동하게 된다.
    /etc/inetd.conf 또는 /etc/xinetd.conf 파일을 살펴보아 ipop3 가 주석처리
    되어 있거나 pop3 가 disable =  yes 로 되어 있지는 않은지 확인한다.
    (3) TCP Wrapper 에 설정되었는지 여부 확인
    /etc./hosts.deny 에 pop3d 접근이 차단되지는 않았는지 확인한다.
    (4) 계정에 Lock 이 걸리지 않았는지 확인
    메일을 받는 과정에서 갑자기 회선이 끊기거나 PC가 다운되는 등 비정상적으
    로 종료시 서버의 pop3d 프로세스가 죽지 않고 계속 남아 있는 경우가 있다.
    이러한 경우 계정에 “Lock 이 걸렸다” 라고 하며 이러한 경우에는 해당 프로
    세스를 찾아 kill 을 하면 된다. 만약 계정에 Lock 이 걸린 상태에서 아웃룩
    익스프레스에서 메일을 수신하려고 하면 아래와 같은 에러가 나게 된다.
    “메일 서버에 로그온하는 데 문제가 있습니다. 지정한 암호가 거부되었습니
    다.
    계정: 'temazone.com', 서버: 'tt.co.kr', 프로토콜: POP3, 서버 응답:
    '-ERR Can't get lock.  Mailbox in use', 포트: 110, 보안(SSL): 아니오,
    서버 오류: 0x800CCC90, 오류 번호: 0x800CCC92”

    (5) Pop3 접속이 많은 경우
    Pop3d 가 서비스되는 inetd는 기본적으로 60초동안 40회의 접속을 받아들이
    도록 (즉, maximum 40회 fork되도록) 설정되어 있다. 따라서 짧은 시간에
    pop3d
    요구가 많을 경우에는 메일로그에 pop3/tcp server failing (looping) 라는 메
    시지가
    나면서 pop3d 데몬 자체가 다운되어 버리므로 동시에 처리 가능한 프로세스의
    한계
    를 적절히 높여주어야 한다.
    이를 위해서는 /etc/inetd.conf 를 열어 아래와 같이 수정하면 된다.

    이전설정)
    pop-3    stream    tcp    nowait    root     /usr/sbin/tcpd    ipop3d

    변경 설정)
    pop-3    stream    tcp    nowait.200    root    /usr/sbin/tcpd    
    ipop3d
    (위의 경우 처리 가능한 프로세스를 200회로 늘려주었다.)
    이후 killall -HUP inetd 를 하면 된다.

    (6) 110 번 포트로 확인
    아래와 같이 pop3d 포트인 110번 포트로 직접 접속하여 수작업으로 확인 가능
    하다.

    # telnet  pop3.tt.co.kr 110           # 110번으로 직접 확인
    Trying 210.17.6.5...
    Connected to pop3.tt.co.kr.
    Escape character is '^]'.
    +OK POP3 pop3.tt.co.kr v2001.76 server ready
    user abc                              # abc 라는 계정으로 접속
    +OK User name accepted, password please
    pass xyz                              # abc 의 암호 xyz 입력
    +OK Mailbox open, 10 messages
    quit                                  # 접속을 끊음.
    +OK Sayonara
    Connection closed by foreign host.

    위의 경우는 정상적인 경우이며 에러가 있을 경우(만약 암호가 다르게 설정되
    었을 경우 -ERR Bad login 와 같은 메시지가 나게 된다.) 각각의 경우에 따라
    에러 메시지를
    각각 확인할 수 있다.

    (7) mail –v 로 확인
    타 서버에서 mail –v antihong at tt.co.kr 와 같이
    메일을 발송하여 정상적으
    로 메일이 도착하는지를 확인해 본다. –v 옵션을 이용하여 메일 발송시에는
    메일 전송의 경로 및 메일 서버간에 주고받는 메시지를 확인할 수 있으므로 문
    제의 원인을 찾는데 도움이 된다.



    특정한 곳으로만 메일이 돌아올 때

    다른 곳은 문제가 없는데, 해외등 특정한 곳으로만 메일이 전송되지 않고 리턴
    되는 경우가 있다. 이러한 경우라면 자신의 메일서버가 mail-abuse.org 의 블
    랙 리스트에 등록되어 있지는 않은지 확인해 볼 필요가 있다. 특히 회신된 메
    일에 “...refused by blackhole site relays.mail-abuse.org” 와 같은 메시
    지가 보인다면 반드시 여부를 확인해 보아야 한다. 적지 않은 메일 서버에서
    는 메일 수신시 실시간으로 이 데이터를 참조하므로 mail-abuse.org 에서 스
    팸 메일 서버로 등록되면 이 기관에 등록된 도메인으로 메일을 보낼 때 받는
    쪽에서는 스팸 메일로 간주하고 수신을 거부하게 된다. 이를 확인하는 방법은
    http://mail-abuse.org/cgi-bin/nph-rss 사이트에서
    메일 서버의 IP 를 조회
    해 보면 된다.  아래는 위 사이트에서 한 IP 에 대해 조회해 본 결과 블랙 리
    스트에 등록되어 있는 것을 보여주고 있다. 이러한 경우라면 조회한 메일 서버
    의 Relay 가 허용되어 스팸 메일 서버로 사용된 적이 있거나 현재 사용되고 있
    다는 뜻이다.  만약 스팸메일 서버로 등록되어 있지 않다면 211.47.65.xxx is
    NOT currently on the RSS list 와 같이 보이게 된다. 






    자신의 메일 서버를 이 블랙리스트에서 제외하려면 먼저 자신의 메일서버에
    Relay 가 허용되어 있는지 확인 후 메일 서버에서 Relay 를 거부 설정한 후 
    If you'd like 211.47.65.135 to be removed from our list, please click
    here. 를 따라 클릭하여 신청을 하면 된다. 이 링크를 클릭하면 신청폼이 나오
    는데, 이 곳에 입력하여 신청을 하면 바로 처리가 된다. Relay 거부 설정을
    한 후 신청을 해야 처리가 되므로 반드시 사전에 Relay 거부 설정을 확인하기
    바란다. 메일 서버의 Relay 여부를 조회하는 방법에 대해서는 본지 10월호
    “철벽 보안을 위한 모니터링 올가이드” 를 참고하기 바란다.


    복수 MX 설정시 주의해야 할 점 

    DNS 서버에서 설정하는 MX 레코드는 해당 호스트로 수신되는 편지를 다른 호스
    트로 라우팅 하도록 한다. 특히 웹서버와 메일 서버를 분리하고자 할 경우 사
    용되는데, 원격 호스트에서 아래와 같이 설정된 도메인 tt.co.kr 로 편지를 송
    신할 경우에 Sendmail이 어떻게 동작하는지 알아보자.


    tt.co.kr.         IN   MX    10     mail1.tt.co.kr.
                   IN   MX     20    mail2.tt.co.kr.
                   IN   MX     20    mail3.tt.co.kr.

    다음은 메일이 수신되는 차례를 보여준다.

    (1) Preference 값이 10으로 가장 낮은 mail1 로 먼저 배달을 시도한다.
    (2) 만약 mail1.tt.co.kr 이 접근이 불가능하면 mail2 혹은 mail3 으로 배달
    을 시도한다.
    (3) (2) 에서 시도한 메일서버로도 접근이 되지 않으면 (2)에서 접근 되지 않
    은 호스트로
      배달을 시도한다. 즉 mail2 로 전송을 시도했다면 mail3 으로 배달을 시도
    한다.
    (4) mail2 와 mail3 서버에 접근이 불가능하다면 자체 큐잉 후, 일정 기간동
    안 주기적으로      
       1-3의 과정을 반복한다.

    흔히 MX 레코드에 대해 잘못 생각하는 것 중 하나는 만약  mail1 이 다운되어
    mail2 로 편지가 배달되었을 때, 편지가 mail2 의 메일 박스에 저장 된다고 생
    각하는 것이다. 만약  이렇게 된다면 유저 입장에서는 메일 수신시 pop3 서버
    를 mail1.tt.co.kr 와 mail2.tt.co.kr 과 같이 여러 개 설정해야 하는 것처럼
    보인다. 그러나 일반적으로 mail2.tt.co.kr 이나 mail3.tt.co.kr 처럼
    Preference 가 높은(즉 우선도가 낮은) 값을 갖는 메일 서버는 큐잉 서버로 동
    작하도록 설정하기 때문에, 결국 메일은 하나의 호스트(mail1)로 모이게 되는
    것이다. 위와 같이 mail2와 mail3 서버가 큐잉 메일 서버로 작동하려면 mail1
    와 mail2의 sendmail 이 아래와 같이 설정되어야 한다.

    (1) 해당 도메인(tt.co.kr)에 대한 인증을 갖지 않아야 한다.
    (즉, mail2 나 mail3 메일 서버의 sendmail.cw 또는 local-host-names 파일에
    tt.co.kr 이 설정되어 있으면 안 된다.)

    (2 )서버는 해당 호스트로의 메일 릴레이(Relay)를 허용하여야 한다.
    (즉, /etc/mail/access 에서 아래와 같이 정의되어야 한다.)
    mail1.tt.co.kr    relay

    인증을 갖지 않아야 한다는 것은 Sendmail의 w 클래스(sendmail.cw(local-
    host-names)  혹은 sendmail.cf의 Cw)에 tt.co.kr 도메인이 설정되지 않아야
    하는 것을 의미하고, 메일 릴레이란 수신되는 편지의 최종 배달지가 자신이 아
    닐 경우, 즉 인증을 갖지 않을 경우 편지를 해당 호스트로 포워딩하는 것을 의
    미한다.  최근의 배포판에서는 기본적으로 sendmail이 릴레이를 거부하도록 설
    정되어 있으므로 메일 큐잉 서버의 경우는 해당 호스트를 목적지로 하는 메일
    에 대해서는 릴레이를 허용하도록 설정하여야 한다는 것을 주의하기 바란다.
    mail1 의 다운으로 인해 mail2 로 전달되는 메일은 메일큐에 저장되어 있으면
    서, 일정 기간(Sendmail.cf에서 지정된 Timeout.queuereturn=5d 만큼)동안 주
    기적(Sendmail 구동시 지정된, 일반적으로 30분 -q30m)으로 mail1 로 배달이
    재시도된다.


    메일 서버의 버전을 숨기는 법

    다른 데몬도 마찬가지이지만 메일 서버 역시 해당 포트로 원격 접속을 해  보
    면 메일 서버의 버전 정보등을 확인할 수  있다. 그러나 시스템 관리자 입장에
    서 보안상의 문제로 현재 운영중인 메일 서버의 버전등을 숨기거나 속이고 싶
    을 때가 있는데. 이러한 경우에는 아래의 방법을 이용하면 된다.

    (1) sendmail 의 경우
      sendmail.cf 파일을 보면 아래와 같은 설정이 있다.
    # SMTP initial login message (old $e macro)
    O SmtpGreetingMessage=$j Sendmail $v/$Z; $b
    이 부분을 적절히 삭제하거나 다른 정보로 입력후 sendmail 을 재가동하면 된
    다.
    필자가 운영하는 메일서버의 경우
    O SmtpGreetingMessage=$j Today and Tomorrow(http://tt.co.kr/) 와 같이

    정하였고 이때 25번 포트로 접속시 보이는 정보는 아래와 같다.

    # telnet tt.co.kr 25
    Trying 211.47.66.50...
    Connected to tt.co.kr.
    Escape character is '^]'.
    220 www10.tt.co.kr ESMTP Today and Tomorrow(http://tt.co.kr/)

    (2) pop3d 의 경우
    pop3d 의 경우 소스에서 직접 수정하여야 하는데, 압축 해제한 디렉토리
    의 /src/ipopd 에 보면 ipop3d.c 파일이 있다. 이 파일을 살펴보면 

    char *version = "2001.75";   /* server version */
    라는 부분이 있는데,  필자가 운영하는 pop3d 의 경우 소스에서
    char *version = "xxxxxxxxxx";   /* server version */
    와 같이 수정 후 컴파일 하였고 이때 110번 포트로 원격 접속시 보이는 정보
    는 아래와 같다.

    # telnet tt.co.kr 110
    Trying 211.47.66.50...
    Connected to tt.co.kr.
    Escape character is '^]'.
    +OK POP3 www10.tt.co.kr vxxxxxxxxxx server ready

    버전외 다른 각종 정보도 수정할 수 있으니 각자 상황에 맞게 적절히 설정하
    기 바란다.


    sendmail 과 관련된 몇 가지 명령어

    >> mail1q
    mailq 프로그램의 목적은 큐잉된(/var/spool/mqueue 에 저장된) mail 메시지
    의 요약된 정보를 보여준다.  네트워크 다운등 어떤 특정한 이유로 바로 발송
    되지 못한 메일은 일차적으로 /var/spool/mqueue 에 큐잉된 상태로 저장된 후
    일정 시간마다 발송을 위해 재시도가 되는데,  현재 큐잉된 메일 메시지의 요
    약 정보를 보려면 아래와 같이 확인할 수 있다.

    # mailq

    /var/spool/mqueue/q1 (2 requests)
    ----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------
    ------
    f7A84oV15068     1446 Fri Aug 10 17:04 nobody
                    (Deferred: Connection timed out with kebi.net.)
                                          darling at kebi.net
    f775ieF24893   521898 Tue Aug  7 14:44 <shlee at
    tt.co.kr
    >
                    (Deferred: Connection timed out with mail.unitel.net.)
                                          <cf1318 at
    unitel.net
    >
    /var/spool/mqueue/q2 is empty
                   /var/spool/mqueue/q3 (1 request)
    ----Q-ID---- --Size-- -----Q-Time----- ------------Sender/Recipient------
    ------
    f775nJF25249   230815 Tue Aug  7 14:49 <shlee at
    tt.co.kr
    >
                    (Deferred: Connection timed out with hanmail.com)
    cuwww23 at hanmail.com

    위 메시지를 보면 어떠한 이유로 메일이 발송되지 못하고 있는지를 추측할 수
    있다.
    3 메시지 모두 수신자의 e-mail 주소를 잘못 기입했기 때문인데, 각각
    kebi.com 인데, kebi.net 으로 unitel.co.kr 인데, unitel.net 으로 ,
    hanmail.net 인데, hanmail.com 으로 도메인 주소를 잘못 기입하여 메일을 발
    송하여 서버에서 메일을 발송하지 못하고 큐에 저장되어 있는 것을 확인할 수
    있다.
    여기에서 주의할 점은 mailq 명령어는 일반 유저로 실행하여 확인이 가능하므
    로 퍼미션을 700 등으로 조절하여 일반 유저들은 실행할 수 없도록 하는 것이
    좋다.

    >> mailstats
    mailstats 프로그램은 현재의 메일 송수신과 관련하여 통계를 보여준다.

      * 현재의 메일 통게를 보려면 아래와 같이 확인할 수 있다.

    # mailstats
    Statistics from Sat Aug 11 04:02:02 2001
    M   msgsfr  bytes_from   msgsto    bytes_to  msgsrej msgsdis  Mailer
    1        0          0K        3        317K        0       0  *file*
    4      690     596691K      824     137070K    68426       0  esmtp
    9       63      12212K        0          0K       27       0  local
    =============================================================
    T      753     608903K      827     137387K    68453       0
    C      753                  827                68453

    이를 적절히 이용하면 mrtg 를 이용해 일정 시간마다 발송되고 수신되는 메일
    의 개수를 통계로 내어 그래프로 볼 수 있다.(본지 10월호, 철벽보안을 위한
    모니터링 올가이드 참조)

    최근 sendmail 관련 버그에 대해

    한동안 문제가 없었던 sendmail 에 최근 들어 몇 가지 보안 문제가 발견되었
    다.
    이 버그는 매우 치명적인 문제인데, 아직 이를 모르고 그대로 사용중인 유저들
    이 많은 것 같다. 각자의 메일 서버에는 해당사항이 없는지 꼭 확인해 보기 바
    란다.

    첫번째로, 8월말에 발표된 버그는 현재 대부분의 메일 서버 프로그램으로 사용
    중인 sendmail 8.11.6 이전 버전에 해당하는 보안버그로서 일반유저가 Local
    에서 root 권한을 얻을 수 있는 매우 치명적인 버그인데, 이미 공격 소스가 여
    러 사이트에 공개되어 있다.
    참고로 이 버그는 8.11.0부터 8.11.5 버전까지만 해당하므로 8.10.x 나 8.9.x
    는 해당되지 않는다.  따라서 아래의 사이트를 참고로 sendmail 을 8.11.6 이
    나 8.12등 최신버전으로 업그레이드하기 바란다.

    8.11.0부터 8.11.5 의 경우 8.11.6 으로 업그레이드하면 되고 8.12.0.Beta 의
    경우 8.12.0.Beta19 이상으로 업그레이드하면 된다. 이에 대해서는
    http://www.securityfocus.com/bid/3163
    http://www.sendmail.org/8.11.html
    를 참고하기 바란다.

    두번째는, 10월초에 발견된 버그로서  모든 버전에 해당하는 문제인데, 이전에
    도 자주 나왔던 문제이다. 바로 shell 접근이 가능한 일반유저가 sendmail
    에 -q 옵션을 사용하여 큐에 있는 메시지를 드롭할 수 있는 문제이다. 아래의
    설명을 보기 바란다.

    [user@net user]$ id
    uid=778(user) gid=778(user)
    [user@net user]$ mailq
                   Mail Queue (1 request)
    --Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient----------
    --
    NAA05248       11 Tue Oct  2 13:03 user1
                    (Deferred: Connection refused by tt.co.kr.)
                                      test at tt.co.kr

    [system@net system]$ /usr/sbin/sendmail -q -h10000
    Too many hops 10000 (25 max): from system via localhost, to test
    at tt.co.kr

    Too many hops 10000 (25 max): from MAILER-DAEMON via localhost, to
    postmaster
    Too many hops 10000 (25 max): from MAILER-DAEMON via localhost, to
    postmaster
    MAILER-DAEMON... Saved message in /usr/tmp/dead.letter
    [user@net user]$ mailq
    Mail queue is empty

    위와 같이 hop count 를 크게 설정함으로써 일반 유저가 현재 큐의 내용을 강
    제적으로 drop 시킬 수 있다.

    세번째는 역시 모든 버전에 해당하는 문제로 일반 유저가 sendmail -q -d0-
    xxxx.xxx 와 같이 사용시 (xxx는 디버깅 레벨이다.) 일반 유저가 메일서버의
    각종 설정 뿐만 아니라 큐에 저장되어 있는 내용, 메시지 경로나 제목, 메일
    소프트웨어등의 정보를 볼 수 있는 문제이다.
    두번째,세번째 문제는 sendmail.cf 에서

    O PrivacyOptions=authwarnings,novrfy,noexpn,restrictqrun
    와 같이 restrictqrun 를 추가함으로써 해결 가능하다.


    기타 메일과 관련된 장애가 확인 시

    지난달 아파치 웹서버의 장애에 대해 이야기하면서 문제나 장애가 발생시에는
    웹서버의 error_log  메시지를 살펴보도록 이야기 했었다.  메일서버도 마찬가
    지이다. 메일서버 장애시는 문제의 원인을 찾기 위해 로그 파일을 살펴보는 습
    관을 들이는 것이 좋다.
    메일 관련 로그는 /var/log/messages 나 /var/log/maillog 파일을 살펴보면 되
    며 로그파일을 보면 여기에서 언급하지 않은 문제가 발생했다 하더리도 어렵
    지 않게 원인을 찾을 수 있을 것이다.   다시 한번 강조하지만 모든 문제의 원
    인과 해결책은 로그에 있다는 것을 명심하기 바란다.
    2006/09/08 23:28 2006/09/08 23:28
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 도시의 매연 위 푸른하늘...
    원본 http://blog.naver.com/savemyface/120006480613
    1. 로케일(Locale)의 의미
    세계 여러 나라들은 각자 다른 문화(언어, 날짜, 시간 등)을 갖고 있다. 프로그램의국제화(Internationalization, 줄여서 i18n)는 사용자로 하여금 프로그램 수행시 로케일이란 것에 의해 입맛에 맞는 환경을 선택할 수 있도록 만든 것을 말한다. 예를 들어 어떤 프로그램의 메시지가 여러가지 언어로 주어져 있는 경우 이중에 어떤 언어의 것을 출력할 것인가를 사용자가 결정할 수 있는 것이다. 그것을 가능하게 해 주는 수단이 바로 로케일이다. 이것은 단순히 메시지 뿐만이 아니고 숫자표현법, 날짜 또는 시간표현법 등 여러가지에 사용될 수 있다. 그것 각각을우리는 카테고리(category)라고 부른다. 카테고리에는 LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME 가 있다.
    2. 로케일 설정방법
    로케일을 지원하는 프로그램의 실행 방식을 선택하기 위해서는 환경 변수 설정을 이용한다. (카테고리 각각에 해당하는 환경변수는 카테고리 이름과 동일하다.)
    로케일 환경 변수에 관한 정보는 locale이란 명령으로 간단히 얻을 수 있다.

    % locale
    LANG=ko_KR.eucKR
    LC_CTYPE="ko_KR.eucKR"
    LC_NUMERIC="ko_KR.eucKR"
    LC_TIME="ko_KR.eucKR"
    LC_COLLATE="ko_KR.eucKR"
    LC_MONETARY="ko_KR.eucKR"
    LC_MESSAGES="ko_KR.eucKR"
    LC_ALL=
    위에서 ko_KR.eucKR은 로케일 값(locale name)이다. 일반적인 로케일 값의 형식은 ll[_CC[.EEEE]][@dddd] 이다. ll은 언어(language)를 지정하는 소문자 두 글자 ISO 639 language code, CC는 지역(territory)를 지정하는 대문자 두 글자 ISO 3166 country code, EEEE는 코드셋(codeset)을 지정하는 문자셋(character set) 또는 인코딩(encoding), dddd는 방언 등의 변종을 구별하기 위한 것(modifier)이다. []로 표시된 내용은 안 쓸수도 있음을 의미한다. 예를 들면 en_US는 미국 영어권, en_CA는 영어권 카나다, de_DE는 독일의 독일어, fr_FR는 프랑스의 프랑스어를 의미한다.
    아무 로케일도 설정하지 않았을 때 glibc에서의 기본 로케일은 C 또는 POSIX (glibc에서는 C 로케일의 alias) 로케일이다.

    % locale -a
    라는 명령을 이용하면 이외에 사용 가능한 로케일의 이름들을 알 수 있다. 다음은 여러가지 환경변수의 역할(카테고리의 경우에는 동시에 카테고리의 역할)에 관한 설명이다.
    ☞ LANG : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다. 하지만 LC_* 환경변수보다 우선 순위가 낮다. LC_ALL이 설정이 안 되어 있고 LC_* 값들이 설정이 따로 설정이 않된 경우 LANG을 변화시키면 LC_ALL을 제외한 로케일 카테고리들의 값이 변경되지만 LC_ALL이 설정 되어 있는 경우 LANG의 변화는 로케일 카테고리들의 값에 영향을 주지 않는다.
    ☞ LC_CTYPE : 문자 분류(알파벳, 숫자, 한글 또는 소문자, 대문자 등등), 변환, 대소문자 비교을 위한 로케일 설정을 의미한다. 이것은 예를 들어 fgetwc(), is*(), isw*(), mblen(), mbtowc(), wcstombs() 등의 함수에 영향을 줄 수 있다.
    ☞ LC_COLLATE : 스트링(string)의 정렬 순서(sort order 또는 collation)를 위한 로케일 설정을 위해 사용된다. 이것은 예를 들어 strcoll(), wcscoll(), strxfrm() 등의 함수에 영향을 줄 수 있다.
    ☞ LC_MESSAGES : 메시지 표현을 위한 로케일 설정. 메시지의 국제화를 위한 catopen(), gettext() 등의 함수에 영향을 줄 수 있다.
    ☞ LC_NUMERIC : 금액이 아닌 숫자 표현(천단위, 소수점, 숫자 그룹핑 등)을 위한 로케일 설정. 예를 들어 strtod(), atof(). 
    ☞ LC_MONETARY : 금액 표현(천단위 구분 문자, 소수점 문자, 금액 표시 문자, 그 위치 등)을 위한 로케일 설정. 예를 들어 strfmon().
    ☞ LC_TIME : 시간과 날짜의 표현(년, 월, 일에 대한 명칭 등)을 위한 로케일 설정 예를 들어 strftime(), strptime().
    ☞ LC_ALL : 모든 카테고리에 대한 로케일 설정을 위한 환경변수이다. 위의 LC_* 및 LANG의 어떤 것보다 우선 순위가 높다. 그리고 LC_ALL을 설정하면 다른 로케일 카테고리의 값들이 LC_ALL의 값의 변경되고 LC_ALL설정을 없애면 다른 로케일 카테고리의 값들은 이전값을 유지한다.
    ☞ LANGUAGE : 로케일의 다중 설정을 위해 gettext에서 사용되는 GNU extension 환경변수로 LC_ALL보다도 우선순위가 높다. 로케일들은 구분문자 : 을 이용하여 우선순위가 높은 순대로 나열된다. 예를 들어 LANGUAGE=en_US:ko_KR
    ☞ LINGUAS : gettext를 사용하는 프로그램 설치시 지정한 언어들의 메시지만을 설치하기 위한 환경변수. 구분 문자는 스페이스이다. 예를 들어 LINGUAS="ko ja"
    로케일을 지원하기 위한 방법 및
    3. 작동 원리
    로케일을 제대로 지원하는 프로그램을 작성하기 위해서는 setlocale()함수를 이용하여 로케일을 설정하고 확인하여야 한다. setlocale()함수는 헤더 파일 locale.h 에 정의되어 있으며 그 프로토타입은 다음과 같다.
    char *setlocale (int category, const char *locale);
    이 함수의 역할은 카테고리 category에 대해 로케일 locale을 설정하고 (물론, 사용 가능한 로케일인 경우), 설정된 로케일값을 리턴하는 것이다.
    locale 부분에 ""을 넣은 다음과 같은 예는
    setlocale (LC_ALL, "");
    적당한 환경변수를 참조하여 로케일을 설정하고 그 값을 리턴한다. 환경변수를 참조하는 우선순위는 위에서 설명한대로 LC_ALL, 그외 카테고리, LANG변수 순이고, 변수값을 알아내면 locale.alias(예를 들어, /usr/share/locale/)를 참조한 후 뒤에서부터 @ . _ 을 단위로 순서대로 잘라가며 사용가능한 로케일을 찾아낸다.
    인수 locale 부분에 NULL을 넣은 다음예는
    locale = setlocale (LC_ALL, NULL);
    로케일 값을 변경시키지 않고 단지 카테고리에 관한 현재 로케일값을 알아내고자 하기 위해 그 리턴값을 사용하는 예이다.
    다음은 함수 setlocale()을 사용하여 임시로 로케일로 변경하는 예이다. (glibc manual에 있는 예)
        #include <stddef.h>
        #include <locale.h>
        #include <stdlib.h>
        #include <string.h>
       
        void
        with_other_locale (char *new_locale,
                           void (*subroutine) (int),
                           int argument)
        {
          char *old_locale, *saved_locale;
       
          /* 현재 로케일명을 알아낸다. */
          old_locale = setlocale (LC_ALL, NULL);
       
          /* setlocale()의 재호출 의해 변경될 것을 대비해 로케일 이름을 미리 복사해 둔다. */
          saved_locale = strdup (old_locale);
          if (saved_locale == NULL)
            fatal ("Out of memory");
       
          /* 로케일을 변경하고 subroutine을 수행한다. */
          setlocale (LC_ALL, new_locale);
          (*subroutine) (argument);
       
          /* 원래의 로케일로 복귀한다. */
          setlocale (LC_ALL, saved_locale);
          free (saved_locale);
        }

    다음은 로케일을 이용하여 날짜/시간을 출력하는 프로그램의 예이다.
    #include <stdio.h>
    #include <locale.h>
    #include <time.h>

    int main(void)
    {
    time_t now;
    struct tm *l_time;
    char string[256];

    /* 환경변수로부터 시간 관련 로케일을 결정한다. */
    setlocale(LC_TIME, "");

    /* calendar 시간을 now라는 변수에 저장.
    * 그 값은 1970년 1월 1일 이후부터 지금까지의 초단위 시간 */
    now = time((time_t *)NULL);

    /* calendar 시간의 다른 유용한 형태를 l_time변수에 저장 */
    l_time = localtime(&now);

    /* 우리가 원하는 포맷의 시간 포맷을 string이라는 변수에 저장 */
    strftime(string, sizeof string, "%c", l_time);

    /* 출력 */
    printf("%s\n", string);

    return 0;
    }
    다음은 위의 파일을 time_test.c라고 저장하고 컴파일하여 c쉘에서 시험하는
    예이다.
    % gcc -o time_test time_test.c
    % setenv LANG ko_KR.eucKR
    % ./time_test
    2000년 01월 12일 수요일 오후 10시 26분 56초
    % setenv LANG C
    % ./time_test
    Wed Jan 12 22:27:22 2000
    2006/09/08 23:28 2006/09/08 23:28
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 무일물(無一物)」
    원본 http://blog.naver.com/fr22m1n/140003752561

    이 글은 KELP의 조형기님 글을 가져와서 수정한 것입니다.

    - 들어가기 -
    리눅스를 잘 알지 못할 당시 나는 리눅스에는 왜 Visual C++가 없는지에 대해 불평하였다. 그런 편리한 IDE환경이 없는지에 대해서 참으로 불만이었다. 어쩔 수 없이 이상한 에디터 vi를 배우기 시작했고, 명령 라인에서 gcc 를 구동하기 시작했었다. 그러다 명령 라인에서 gcc 를 계속 두들기니까... 뭐 편한 거 없나 ? 하고 살펴보고, 즉시 make 를 공부했다. 지금까지 이런 과정을 거치면서 리눅스의 전통적인 아니 유닉스의 전통적인 개발 환경과 개발 방법이 아주 매력적이라는 사실을 알게 되었다.
    사실 알고 보면 Visual C++의 느낌표를 누르면 이러한 과정이 내부에서 일어나는 것이다. 우리 눈 앞에 안 보일 뿐이다. 나는 이 사실을 깨달았을때 Visual C++/MFC에 정이 뚝 떨어졌다. 지금도 어쩔 수 없는 초보이지만, 그러기에 나름대로 유닉스의 개발환경에 대하여 알아 본다.

    - 개요도 -
    이번에는 리눅스의 개발 환경이 전체적으로 어떻게 구성되어 있나 살펴보는 것이다. 우선 분류를 하여 나열해 보겠다.

    [1] GNU Toolkit
      1) Binutils
      2) GCC
      3) GDB
      4) C, C++ library

    [2] 디버깅 도구
      1) GDB
      2) DDD
      3) kdbg
      4) ldd
      5) strace
      6) ltrace
      7) checker

    [3] 시간측정, 성능평가도구
      1) time
      2) gprof
      3) calls

    [4] 자동 컴파일링 도구
      1) make
      2) m4
      3) Automake
      4) Autoconf

    [5] 인터페이스 만들기 도구
      1) Xt
      2) Motif/Lesstif
      3) Xaw3D
      4) Tcl/Tk
      5) QT
      6) GTK+

    [6] 버전 관리 도구
      1) CVS
      2) RCS
      3) SCCS

    [7] 파일 패치 & 들여쓰기
      1) patch
      2) diff
      3) indent

    한눈에 들어오니까 참 좋다. 이것을 보고 있으면 마음이 편안해진다. 빠진 내용이 있으면 피드 백을 해 주기 바란다. 여기에 나열되어 있는 모든 것들을 어느 정도 안다면 글쎄 유닉스/리눅스 초보는 분명 아닐 것이다. 위에서 [1] 항목은 분류항목으로 있기에 좀 그렇지만 대표적이라서 그냥 넣어 두었다.

    - 본론 -
    그럼 이제 하나하나 항목에 대해서 대충 알아보자. 이 내용들은 필자의 기반 지시과 '러닝 리눅스' 라는 책을 참고하였다. 이 책을 지은 '메트 웰시'라는 작자는 보통 사람은 아닌 것 같다. (www.linuxdoc.org 의 핵심 관리자이다.)

     [1] GNU toolkit
      1) Binutils - 여기에는 어셈블러(as), 링커(ld) 를 비롯하여 많은 바이너리 도구들이 포함되어 있다.
       ld - GNU 링커.
       as - GNU 어셈블러. ( 임베디드 리눅스를 하면서 어셈블리어는 필수겠죠?)
       addr2line - 주소를 파일명과 라인 수로 변경.
       ar - 정적 라이브러리를 만드는 유틸리티. (예 $ ar rs libxxx.a a.o b.o s옵션을 넣으면 ranlib 를 실행하지 않아도 된다.)
       c++filt - Filter to demangle encoded C++ symbols.
       gprof - 프로파일 정보 출력(프로파일러)
       nlmconv - 오브젝트 코드를 NLM으로 변경
       nm - 오브젝트 파일의 심볼들을 나열.
       objcopy - 오브젝트 파일을 복사 및 변환
       objdump - 오브젝트 파일을 덤프하여 여러가지 정보를 보여줌. 어셈블리어도 보여줌
       ranlib - 정정 라이브러리를 만들고 나서 인덱스 파일을 라이브러리 처음에 생성 시켜줌
       readelf - ELF 포맷의 오브젝트 파일의 정보 출력
       size - 오브젝트 또는 문서 파일의 정보 출력, text , data , bss, dec 등의 섹션 크기를 출력 (예 $ size any_program)
       strings - 파일로부터 출력 가능한 스트링 나열
       strip - 심볼 제거, 프로그램의 사이즈를 조금이라도 줄일려고 임베디드에선 많이 사용.
       windres - 윈도우즈용 파일을 위한 컴파일러
        ** 이런 바이너리 유틸리티를 능숙하게 다루는 것이 임베디드 리눅스 프로그래머에겐 필수이다.
        ** 그래서 나도 시간나는 데로 틈틈히,열심히 매뉴얼들을 읽고 있다. 시스템 프로그래밍의 기본이다.
      2) GCC - gcc에 대한 안내를 보라.
      3) GDB - 나는 명령라인에서 디버깅하는 프로그램. DDD라는 프로그램도 있다.
      4) c, c++ library - glibc 가 표준 C언어 라이브러이다.
       현재 나의 리눅스 머신에는 /lib/libc-2.2.2.so 라는 공유라이브러리로 존재한다.
       c++ 표준 라이브러리는 /usr/lib/libstdc++-3-libc6.2-2-2.10.0.so 라는 공유라이브러리로 존재한다.
       c library는 시스템 유틸리티들이 다 사용하기 때문에, c++ library 는 그렇지 않으니까, /usr/lib에 존재한다.
       물론 위의 두 개다 /usr/lib에 정적 라이브러리들로도 다 있다.
       표준 라이브러리의 소스는 www.gnu.org의 GNU Software 란에 다 있다.

     [2] 디버깅 도구
      1) gdb - 진짜 디버깅 툴
      2) ddd - GDB의 윈도우용 프론트 엔드
      3) kdbg - GDB의 윈도우용 프론트 엔드
       막강한 기능들을 많이 가지고 있다. 위의 프로그램 중에서는 ddd를 가장 많이 사용하는 것 같다.
       kdbg는 kde기반에서 나온것 같은데, kdevelop이라는 QT용 IDE툴의 기본 디버거로 들어가 있다.
      4) ldd - 공유 라이브러리 의존성을 출력해 준다. 불필요한 라이브러리는 제거하는 것이 좋다.
      5) strace / ltrace - 뭔가 추적하는 것이다.
       strace는 사용하는 시스템 콜을 추적하여 주는 것이고,
       ltrace는 라이브러리 호출을 추적하여 주는 것이다.
       지금 당장, hello world c언어 소스를 컴파일하여 실행하여 보라.
       그리고 strace/ltrace 를 실행하고 유심히 살펴보라. 감이 올 것이다!
        $ strace ./hello
       $ ltrace ./hello

      6) checker - 프로그램 코딩중 메모리 할당 루틴에서 문제가 있는 것 같으면, 사용하는 것이다.
       컴파일하기 전에 -lchecker 라는 옵션을 주는 것을 잊지 말자.
       그리면 문제가 있는 메모리 할당 루틴을 checker 가 검사하여 원인을 보고 하여 줄 것이다.

     [3] 시간 측정, 성능 평가 도구
      1) time - 프로그램의 수행 시간을 측정해 준다. 시스템 유틸리티이지만, 같은 이름의 라이브러리 함수가 있다.(man 2 time)
      2) gprof - 바이너리 유틸리티에 포함되어 있다. 이것은 프로파일러이다.
       즉, 코드 안에서 병목 현상을 일으키는 곳을 파악할 수 있다.
       각 함수가 얼마나 자주 호출되는지, 각 함수에서 소요된 시간 등 실행한 프로그램의 목록을 보여주는 도구이다.
       컴파일 할때 -pg 옵션을 주고 해야 한다. 컴파일 후 실행하라.
       정상적으로 종료하면, 현재 디렉토리에 gmon.out 이라는 파일을 내어 놓는다.
       이 파일안에 실행 프로파일 정보가 들어 있으며 gprof를 사용하여 통계값을 볼 수 있다.
        $ gprof 프로그램명 gmon.out
      3) calls - c 소스 코드 안에서의 호출 관계를 계층 구조로 보여 준다.
       호출된 모든 함수의 인덱스를 만들거나 프로그램 구조에 대한 계층 구조 보고서를 작성할 때 좋다.
        $ calls hello.c

     [4] 자동 컴파일링 도구
      1) make - 조금이라도 덩치 있는 프로그램을 작성해 보았다면 필요성을 절실히 느낄 것이다.
       make를 사용할 줄 모른다면, 남이 작성한 파일을 보고 수정할 수 있으면 된다.
       그러다 보면 자신만의 makefile을 만들수 있을 것이다.
      2) m4 / automake / autoconf - 플랫폼에 독립적인 프로그램을 배포할 때 필요한 것들이다.
       make 파일을 작성하는 것이 또 지루한 작업이기 때문에 그것을 자동으로 해주는 툴이 automake이다.
       autoconf는 configure 라는 스크립트를 자동으로 작성해 주는 툴이다.
       우리가 프로그램을 설치할때 리눅스에서, 가장 먼저, ./configre 하지 않는가?
       그 configure 스트립트를 만들어 주는 것이 autoconf 이다.
       configure 라는 스트립트는 여러가지를 시스템에서 찾아보고, 알맞은 makefile을 만들어 주는 것이다.
       그후에 make 명령을 이용해서 컴파일을 시키는 것이다.
       m4는 매크로 프리 프로세서라는 것이다. aotoconf에서 내부적으로 사용하는 것이다.

     [5] 인터페이스 만들기 도구
      1) Xt - X library의 기본 툴킷이다.
      2) Motif / Lesstif - 유닉스상에서 전통적으로 인기있는 윈도우 툴킷이지만 상용이다.
       오픈소스의 다음 세대(QT, GTK+)들에게 대세를 빼았기었다. 그리고 Lesstif 가 나왔지만 대세는 홀러간 뒤었다.
      3) Xaw3D - 표준 아데나(Athena)위젯의 변형 버전으로써 마치 모티프와 같은 스타일의 3D 효과를 준다.
      4) Tcl/Tk - 창, 버튼, 스크롤바 등 기존의 프로그램에서 사용하고 있는 X 기반의 완전한 인터페이스를 만들 수 있다.
      5) Qt - 트롤 테크(Troll Tech)가 만든 C++ GUI 툴킷이다.
       나는 QT로 윈도우 프로그래밍을 즐긴다. 왜냐면, 예쁘기 때문이다. 나는 뭐니뭐니 해도 예쁜게 좋다.
       gtk기반의 어플리케이션은 알고리즘이나 성능을 좋더라도, 보기에 좋지는 않다.
      6) GTK+ - 원래 김프라는 이미지 처리 프로그램을 위해 만든 C GUI 툴킷이다.

     [6] 버전 관리 도구
      1) CVS - (Concurrent Versioning system) 거의 표준으로 자리 잡고 있다. 인터넷으로 전세계 개발자들이
       함께 개발할 수 있게끔 해주는 멋진 도구이다. 거의 모든 오픈 소스 프로젝트들이 CVS로 개발되고 있다.
      2) RCS - (Revision control system) CVS와 비슷하다. RCS로는 한 그룹내에서 개발할때 사용한다.
      3) SCCS - (Source Code Control System) 카네기 멜론 대학에서 개발된 것이다.

     [7] 파일 패치 & 들여 쓰기
      1) patch - 정기적으로 갱신되는 프로그램이 있고 프로그램이 매우 많은 소스 파일로 이루어져 있으며
       한 버전에서 다음 버전으로 갱신하려고 상황에 맞게 파일을 변환시켜주는 프로그램이다.
       매번 전체 소스 배포 파일을 내놓는 것이 적절치 않을 때에 주로 사용한다.
       방법은 각 버전마다 변경된 부분만을 patch로 갱신하는 것이다.
      2) diff - patch보다 작은 규모의 업그레이드에 유용하게 사용된다.

      <사용법>
        $ patch -pNUM〈 patchfile
       $ diff [option] from-file to-file


      < 예제1. 소스가 단순 파일 하나일 때 >
      hello1.c 가 있고, 다음 버전인 hello2.c 가 있다고 하자.
      우선 hello.patch 라는 패치 파일을 만들어 내려면 다음과 같이 한다.
        $ diff -c hello1.c hello2.c > hello.patch
      이렇게 만든 패치 파일을 배포하며, 이 패치 파일을 다운 받은 사용자는 다음과 같이 하여 hello1.c 소스에 패치를 가한다.
        $ patch〈 hello.patch

      < 예제2. 소스가 디렉토리 구조일 때 >
      hello1 라는 디렉토리가 있고, 다음 버전인 hello2라는 디렉토리가 있다고 하자.
      우선 hello.patch 라는 패치 파일을 만들기 위해서는 다음과 같이 한다.
        $ diff -cr hello1 hello2 > hello.patch ( 옵션 -r 은 recursive를 의미 )
      이렇게 만든 패치 파일을 배포하며, 이 패치 파일을 다운 받은 사용자는 다음과 같이 hello1 디렉토리 구조에 패치를 가한다.
        $ patch -p0〈 hello.patch (-pNUM 에 대한 옵션은 맨페이지 참고)

      3) indent - 코드를 예쁘게 들여쓰기를 해준다. 다음과 같이 사용할 수 있다.
        $ indent hello.c

    출처 : 엠파스블로그 > 입으로 하는 행동, 손으로 하는 생각.

    > 테마 : Programming?

    2006/09/08 23:27 2006/09/08 23:27
    이 글에는 트랙백을 보낼 수 없습니다
    Linux/SHELL  2006/09/08 23:25
    grep 계열 명령어

    grep 명령어

    grep의 의미

    grep : 파일 전체를 뒤져 정규표현식에 대응하는 모든 행들을 출력한다.
    egrep : grep의 확장판으로, 추가 정규표현식 메타문자들을 지원한다.
    fgrep : fixed grep 이나 fast grep으로 불리며, 모든 문자를 문자 그래도 취급한다. 즉, 정         규표현식의 메타문자도 일반 문자로 취급한다.

    3.1.2 grep의 동작 방법

    grep에서 사용하는 정규표현식 메타문자
    메타문자
    기    능
    사용 예
    사용 예 설명
    ^
    행의 시작 지시자
    '^love'
    love로 시작하는 모든 행과 대응
    $
    행의 끝 지시자
    'love$'
    love로 끝나는 모든 행과 대응
    .
    하나의 문자와 대응
    'l..e'
    l 다음에 두 글자가 나오고 e로 끝나는 문자열을 포함하는 행과 대응
    *
    선행문자와 같은 문자의 0개 혹은 임의개수와 대응
    ' *love'
    0개 혹은 임의 개수의 공백 문자 후에 love로 끝나는 문자열을 포함한 행과 대응
    []
    [] 사이의 문자 집합중 하나와 대응
    '[Ll]ove'
    love나 Love를 포함하는 행과 대응
    [^ ]
    문자집합에 속하지 않는 한 문자와 대응
    '[^A-K]love'
    A와 K 사이의 범위에 포함되지 않는 한 문자와 ove가 붙어있는 문자열과 대응
    \<
    단어의 시작 지시자
    '\<love'
    love로 시작하는 단어를 포함하는 행과 대응(vi,grep에서 지원)
    \>
    단어의 끝 지시자
    'love\>'
    love로 끝나는 단어를 포함하는 행과 대응
    (vi,grep에서 지원)
    \(..\)
    다음 사용을 위해 태그를 붙인다.
    '\(lov\)ing'
    지정된 부분을 태크1에 저장한다. 나중에 태그값을 참고하려면 \1을 쓴다. 맨 왼쪽부터 시작해 태그를 9개가지 쓸 수 있다. 왼쪽 예에서는 lov가 레지스터1에 저장되고 나중에 \1로 참고할 수 있다.
    x\{m\}
    문자 x를 m번 반복한다.
    'o\{5\}'
    문자 o가 5회 연속적으로 나오는 모든 행과 대응
    x\{m,\}
    적어도 m번 반복한다.
    'o\{5,\}'
    문자 o가 최소한 5회 반복되는 모든 행과 대응
    x\{m,n\}
    m회 이상 n회 이하 반복한다.
    o\{5,10\}'
    문자 o가 5회에서 10회 사이의 횟수로 연속적으로 나타나는 문자열과 대응

    grep의 옵션
    옵션
    동작 설명
    -b
    검색 결과의 각 행 앞에 검색된 위치의 블록 번호를 표시한다. 검색 내용이 디스크의 어디쯤 있는지 위치를 알아내는데 유용하다.
    -c
    검색 결과를 출력하는 대신, 찾아낸 행의 총수를 출력한다.
    -h
    파일 이름을 출력하지 않는다.
    -i
    대소문자를 구분 하지 않는다.(대문자와 소문자를 동일하게 취급).
    -l
    패턴이 존재하는 파일의 이름만 출력한다.(개행문자로 구분)
    -n
    파일 내에서 행 번호를 함께 출력한다.
    -s
    에러 메시지 외에는 출력하지 않는다. 종료상태를 검사할 때 유용하게 쓸 수 있다.
    -v
    패턴이 존재하지 않는 행만 출력한다.
    -w
    패턴 표현식을 하나의 단어로 취급하여 검색한다.

    # grep -n '^jack:' /etc/passwd
    (/etc/passwd 파일에서 jack을 찾는다. jack이 행의 맨 앞에 있으면 행 번호를 화면으로 출력한다.)

    3.1.3 grep과 종료 상태
    grep은 파일 검색의 성공 여부를 종료 상태값으로 되돌려준다.
    패턴을 찾으면 0, 패턴을 찾을 수 없으면 1, 팡리이 존재하지 않을 경우 2
    sed,a자 등은 검색의 성공 여부에 대한 종료 상태값을 반환하지 않는다. 다만 구문 에러가 있을 경우에만 에러를 보고한다.

    3.2 정규표현식을 사용하는 grep의 예제
    # grep NW datafile
    # grep NW d*
    (d로 시작하는 모든 파일에서 NW를 포함하는 모든 행을 찾는다.)
    # grep '^n' datafile
    (n으로 시작하는 모든 행을 출력한다.)
    # grep '4$' datafile
    (4로 끝나는 모든 행을 출력한다.)
    # grep TB Savage datafile
    (TB만 인자이고 Savage와 datafile은 파일 이름이다.)
    # grep 'TB Savage' datafile
    (TB Savage를 포함하는 모든 행을 출력한다.)
    # grep '5\.' datafile
    (숫자 5, 마침표, 임의의 한 문자가 순서대로 나타나는 문자열이 포함된 행을 출력한다.)
    # grep '\.5' datafile
    (.5가 나오는 모든 행을 출력한다.)
    # grep '^[we]' datafile
    (w나 e로 시작하는 모든 행을 출력한다.)
    # grep '[^0-9]' datafile
    (숫자가 아닌 문자를 하나라도 포함하는 모든 행을 출력한다.)
    # grep '[A-Z][A-Z] [A-Z]' datafile
    (대문자 2개와 공백 1개, 그리고 대문자 하나가 연이어 나오는 문자열이 포함된 행을 출력한다.)
    # grep 'ss* ' datafile
    (s가 한 번 나오고, 다시 s가 0번 또는 여러번 나온 후에 공백이 연이어 등장하는 문자열을 포함한 모든 행을 출력한다.)
    # grep '[a-z]\{9\}' datafile
    (소문자가 9번 이상 반복되는 문자열을 포함하는 모든 행을 출력한다.)
    # grep '\(3\)\.[0-9].*\1 *\1' datafile
    (숫자 3,마침표,임의의 한 숫자,임의 개수의 문자,숫자 3(태그),임의 개수의 탭 문자,숫자 3의 순서를 갖는 문자열이 포한된 모든 행을 출력한다.)
    # grep '\<north' datafile
    (north로 시작하는 단어가 포함된 모든 행을 출력한다.)
    # grep '\<north\>' datafile
    (north라는 단어가 포함된 모든 행을 출력한다.)
    # grep '\<[a-z].*n\>' datafile
    (소문자 하나로 시작하고, 이어서 임의 개수의 여러 문자가 나오며, n으로 끝나는 단어가 포함된 모든 행을 출력한다. 여기서 .*는 공백을 포함한 임의의 문자들을 의미한다.)

    3.3 grep에 옵션 사용
    # grep -n '^south' datafile
    (행번호를 함께 출력한다.)
    # grep -i 'pat' datafile
    (대소문자를 구별하지 않게 한다.)
    # grep -v 'Suan Chin' datafile
    (문자열 Suan Chin이 포함되지 않은 모든 행을 출력하게 한다. 이 옵션은 입력 파일에서 특정 내용의 입력을 삭제하는데 쓰인다.
    # grep -v 'Suan Chin' datafile > black
    # mv black datafile
    )
    # grep -l 'SE' *
    (패턴이 찾아진 파일의 행 번호 대신 단지 파일이름만 출력한다.)
    # grep -w 'north' datafile
    (패턴이 다른 단어의 일부가 아닌 하나의 단어가 되는 경우만 찾는다. northwest나 northeast 등의 단어가 아니라, north라는 단어가 포함된 행만 출력한다.)
    # grep -i "$LOGNAME" datafile
    (환경변수인 LOGNAME의 값을 가진 모든 행을 출력한다. 변수가 큰따옴표로 둘러싸여 있는 경우, 쉘은 변수의 값으로 치환한다. 작은따옴표로 둘러싸여 있으면 변수 치환이 일어나지 않고 그냥 $LOGNAME 이라는 문자로 출력된다.)

    3.4 egrep
    egrep(extended grep) : grep에서 제공하지 않는 확장된 정규표현식 메타문자를 지원  한다.
                                        grep와 동일한 명령행 옵션을 지원한다.
    egrep에서 지원하는 확장 메타문자
    메타문자
    기능
    사용 예
    사용 예 설명
    +
    선행문자와 같은 문자의 1개 혹은 임의 개수와 대응
    '[a-z]+ove'
    1개 이상의 소문자 뒤에 ove가 붙어있는 문자열과 대응. move,approve,love,behoove 등이 해당된다.
    ?
    선행문자와 같은 문자의0개 혹은 1개와 대응
    'lo?ve'
    l 다음에 0개의 문자 혹은 하나의 문자가 o가 나오는 문자열과 대응. love,lve 등이 해당된다.
    a|b
    a 혹은 b와 대응
    'love|hate'
    love 혹은 hate와 대응.
    ()
    정규표현식을 묶어준다
    'love(able|ly)'
    lovable 혹은 lovely와 대응.
    '(ov)+'
    ov가 한 번 이상 등장하는 문자열과 일치.

    3.4.1 egrep 예제
    # egrep 'NW|EA' datafile
    (NW나 EA가 포함된 행을 출력한다.)
    # egrep '3+' datafile
    (숫자 3이 한 번 이상 등장하는 행을 출력한다.)
    # egrep '2\.?[0-9]' datafile
    (숫자 2 다음에 마침표가 없거나 한 번 나오고, 다시 숫자가 오는 행을 출력한다.)
    # egrep ' (no)+' datafile
    (패턴 no가 한 번 이상 연속해서 나오는 행을 출력한다.)
    # egrep 'S(h|u)' datafile
    (문자 S 다음에 h나 u가 나오는 행을 출력한다.)
    # egrep 'Sh|u' datafile
    (패턴 Sh나 u를 포함한 행을 출력한다.)

    3.5 고정 grep 과 빠른 grep
    fgrep : grep 명령어와 동일하게 동작한다. 다만 정규표현식 메타문자들을 특별하게 취급하지
             않는다.
    # fgrep '[A-Z]****[0-9]..$5.00' file
    ([A-Z]****[0-9]..$5.00 이 포함된 행을 출력한다. 모든 문자들을 문자 자체로만
    2006/09/08 23:25 2006/09/08 23:25
    이 글에는 트랙백을 보낼 수 없습니다
    Linux/SHELL  2006/09/08 23:12
    출처 블로그 > 수진오빠 개그소매상
    원본 http://blog.naver.com/soojin001/140005615267
    - 본 쉘 프로그래밍 -

    2001년 1월 13일
    written by 허정수(wertyu@nownuri.net)

    1. 왜 쉘 프로그래밍을 배워야 하는가?
    이 글을 읽는 사람들 중에서는 왜 쉘 프로그래밍을 배워야 하는지 아는 사람도 있고, 모르는 사람도 있을 것이다. 21 세기, 리눅스를 사용하기도 많이 편리해지고, X 윈도를 실행해서 버튼 몇 개만 클릭하면 편하게 사용할 수 있는데 왜 어려운 쉘 프로그래밍을 배워야 하는지 모르는 사람도 있을 것이다.

    하지만, 리눅스를 어느 정도 사용해 본 사람이라면, 리눅스를 편하게 사용하기 위해서 쉘의 사용법과 쉘 프로그래밍을 꼭 알아야 하는 것을 알고 있을 것이다. 어느 책에서는 MS Windows와 유닉스/리눅스의 가장 큰 차이점을 바이너리와 텍스트로 설명하고 있다. 즉, MS Windows는 바이너리 유닉스는 텍스트이다. MS Windows는 모든 설정을 바이너리로 관리하여 사용자가 직접 프로그램의 설정을 변경할 수 없고, 설정을 변경하기 위해서는 꼭 설정을 변경하는 프로그램을 통해야만 한다.(regedit 처럼) 하지만 유닉스는 모든 설정을 텍스트 파일로 관리한다. (요즘 MS Windows도 Script를 이용하여 설정을 바꿀 수 있도록 변하고 있는 추세이다. 즉 유닉스의 장점을 MS Windows도 이해하고 따라가고 있다.)

    이 극명한 차이가 쉘 프로그래밍을 배워야 하는 이유이다. 예를 들어 설명해 보자. 시스템 교체를 위해 MS Windows와 유닉스의 사용자 1만 명을 다른 시스템으로 옮긴다고 생각해 보자. MS Windows에서는 분명 사용자 추가하는 프로그램을 실행하여 각 1만 명의 아이디와 암호 및 프로필을 손수 입력해야 할 것이다. 아무리 클릭을 빠르게 하고, 타이핑이 아무 빨라고 많은 시간이 필요하다. 하지만, 유닉스에서는 간단하게 스크립트를 짜서 실행하면 된다.

    다른 예도 있다. 다음과 같이 현재 디렉터리에 확장자가 gif인 파일이 많이 있다고 하자.

    13:28[wertyu@inos test]$ ls
    a.gif b.gif c.gif d.gif mmv.sh*

    그런데, 여기 있는 gif 파일의 확장자를 모두 jpg로 바꾸려고 한다. 앞의 예에서는 파일이 4개 밖에 안 되지만 만약, 파일이 1000개 라면 당신은 어떻게 할 것인가. 이 때 간단히 스크립트를 짜서 실행하면 쉽게 확장자를 고칠 수 있다. 다음의 스크립트는 확장자가 gif인 파일의 확장자를 jpg로 바꾸는 스크립트이다.(프롬프트 앞의 13:13은 필자의 프롬프트에서 시간을 나타낸다.)

    13:31[wertyu@inos test]$ cat mmv.sh
    #! /bin/sh

    X=`ls *.gif`
    for B in $X
    do
    temp=`basename $B .gif`
    mv $B $temp.jpg
    done

    13:31[wertyu@inos test]$ ls
    a.gif b.gif c.gif d.gif mmv.sh*
    13:31[wertyu@inos test]$ ./mmv.sh
    13:31[wertyu@inos test]$ ls
    a.jpg b.jpg c.jpg d.jpg mmv.sh*

    어떤가 쉽지 않은가?

    2. How the Shell Interpret What You Typed

    이번 절에서는 아주 간단히 쉘이 어떻게 작동하는지 알아 보려 한다. 이번 절의 제목을 해석해 보면, "쉘은 당신이 입력한 것을 어떻게 해석하는가"(How the Shell Interpret What You Typed)이다. 쉘이 작동하는 방법을 조금이나마 이해하기 바란다. 다들 알고 있겠지만, 쉘은 리눅스에서 명령을 내리는데 가장 중요한 프로그램이다.(MS Windows에서의 Shell은 Internet Explorer이다. 알고 있었나?). 쉘은 명령을 내리기 위해서는 어쩔 수 없이 거쳐야 하는 프로그램이기 때문에 쉘이 작동 원리를 이해하면 명령을 쉽고 빠르고 간단하게 입력할 수 있다. 또한 쉘이 작동하는 원리를 정확히 이해해야만 쉘 프로그램도 잘 짤 수 있다.

    다음의 예를 보자. 다음과 같이 간단한 C로 작성한 프로그램이 있다.

    13:42[wertyu@inos test]$ cat how.c
    #include <stdio.h>

    void main(int argc, char* argv[])
    {
    int cnt ;

    for( cnt = 1 ; cnt < argc ; ++cnt )
    {
    printf("arguement %d = %s
    ", cnt , argv[cnt] ) ;
    }
    }

    이 프로그램을 how라는 실행 파일로 컴파일 해 놓자.

    문제 1.
    다음의 실행 결과는 무었인가?

    $ how $HOME

    을 실행 시키면 출력 결과는 무었일까? 이 문제는 쉬울 것이다.

    답 1.

    13:47[wertyu@inos test]$ ./how $HOME
    arguement 1 = /home/wertyu
    13:47[wertyu@inos test]$

    문제 2.

    디렉터리에 다음과 같은 파일들이 있다.

    13:48[wertyu@inos test]$ ls
    a.jpg b.jpg c.jpg d.jpg how* how.c mmv.sh*

    다음을 실행하면 무엇이 출력 될까.

    13:48[wertyu@inos test]$ ./how *

    이건 조금 어렵다. 쉽게 맞출 수 있는 사람도 있겠지만, 대부분의 사람들은 '*'가 출력된다고 답할 것이다. 그러나 답은....

    답 2.

    13:48[wertyu@inos test]$ ./how *
    arguement 1 = a.jpg
    arguement 2 = b.jpg
    arguement 3 = c.jpg
    arguement 4 = d.jpg
    arguement 5 = how
    arguement 6 = how.c
    arguement 7 = mmv.sh
    13:49[wertyu@inos test]$

    위의 두 문제를 풀어 봄으로서 대충이나마 쉘의 작동 방법을 이해할 수 있었을 것이다.

    3. 쉘 스크립트를 작성해 보자.

    이제 기본적인 설명은 끝났으므로 실제 쉘 스크립트를 작성해 보자. 쉘 스크립트의 첫 줄은 항상 다음과 같이 시작을 해야 한다.

    #! /bin/sh

    이 첫 줄은 인터프리터를 지정하는 줄이다. 앞으로 나올 여러 명령들을 인터프리트할 프로그램을 지정한다. 마찬가지로 awk로 스크립트를 작성하기 위해서는 스크립트의 첫 줄은 #! /bin/awk로 시작해야 할 것이다.

    쉘 스크립트를 작성하는 방법은 간단한다. 사용하기 편한 에디터로 명령들을 적은 후에 파일의 모드를 '실행' 모드를 주는 것이다. 다음의 예를 보자


    14:01[wertyu@inos test]$ cat > echo.sh
    #! /bin/sh
    echo $1

    14:02[wertyu@inos test]$ chmod 775 echo.sh
    14:02[wertyu@inos test]$ ./echo.sh Parameter
    Parameter
    14:02[wertyu@inos test]$

    위의 예를 보면 알 수 있듯이 각자 사용하기 편리한 에디터로 스크립트를 작성한 후 chmod 명령으로 파일에 실행 권한을 주어 실행 할 수 있다. 참고로 앞에 나온 echo.sh은 입력받은 parameter 중 첫 번째 parameter를 출력하는 쉘 스크립트이다.

    3.1 변수의 선언 및 사용법

    쉘 프로그램에서 변수를 선언하는 방법을 알아 보자. 변수는 간단히

    변수명=변수값

    과 같이 선언할 수 있다. 여기서 중요한 것은 '변수명'과 '=', '변수값' 사이에 공백이 있으면 안 된다는 것이다. 따라서 다음과 같은 쉘 프로그램은 잘못된 것이다.

    14:07[wertyu@inos test]$ cat wrong.sh
    #! /bin/sh
    x = 123
    echo $x
    14:07[wertyu@inos test]$ ./wrong.sh
    ./wrong.sh: x: command not found

    'x = 123' 부분을 'x=123'과 같이 수정한 후 실행 시키면 123이 출력되는 것을 볼 수 있다.

    선언한 변수를 사용하기 위해서는 앞의 예와 같이 변수명 앞에 $를 붙여주면 된다.

    3.2 Flow of Control
    Flow of Control이란 한글 책에서 흔히 '흐름 제어'로 번역되는 단어로서 '조건 분기문' '루프' 등을 나타낸다. 어떠한 프로그램이든 그 프로그램을 구성하는 프로그램 logic 중 80%는 Flow of Control일 정도로 어떤 language를 배우든 Flow of Control을 익히는 것은 매우 중요하다.

    3.2.1 if 문

    본 쉘 프로그래밍에서 if문은 다음과 같이 사용된다.

    if test_statement_A
    then
    statement_B
    statement_C
    else
    statement_D
    fi

    다음의 예를 보자

    14:36[wertyu@inos test]$ cat test.sh
    #! /bin/sh

    if [ $# -eq 0 ]
    then
    echo "No arguement"
    else
    echo "There are $# arguement(s)"
    fi
    14:36[wertyu@inos test]$ ./test.sh
    No arguement
    14:36[wertyu@inos test]$ ./test.sh a b c d e
    There are 5 arguement(s)

    여기서도 중요한 것은 '[' 와 조건을 검사하는 부분과 ']' 사이에 공백이 있어서는 안 된다는 것이다.
    '$#' 변수는 본쉘 스크립트의 특수 변수로서 인자의 수를 나타내는 변수이고, -eq는 equal의 약자로서 두 수가 같은지 비교하는 연산자 이다.

    if [ $# -eq 0 ] 은 다음과 같이 바꾸어 사용해도 된다.

    if test $# -eq 0

    즉, 앞의 test.sh 스크립트는 다음의 스크립트와 동일하게 동작한다.

    14:42[wertyu@inos test]$ cat test.sh
    #! /bin/sh

    if test $# -eq 0
    then
    echo "No arguement"
    else
    echo "There are $# arguement(s)"
    fi

    test는 외부 명령으로서 주어진 expression을 검사하여 true or false를 return하는 명령이다. 여기서 test를 예로 든 것은 if 의 조건에는 외부 명령이 함께 쓰일 수 있기 때문이다. 즉, 다음 스크립트와 같이 작동하는 스크립트를 작성할 수 있다.

    if ls plot.ps
    then
    lpr plot.ps
    else
    echo ":::: ERROR FILE DOESN'T EXIST ::::"
    fi

    앞의 예제 스크립트는 plot.ps라는 파일이 있을 경우에 프린트를 하고, plot.ps라는 파일이 없을 경우에는 에러 메시지를 출력하는 스크립트이다.


    3.2.2 숫자의 비교

    앞의 예에서 -eq로 두 수의 값이 같은지 비교하는 것을 보았다. -eq 외에도 많은 연산자가 있다.

    -eq : equal, 두 수가 같냐?
    -ne : not equal, 두 수가 같지 않냐?
    -gt : greater than, 왼쪽 변수가 오른쪽 변수보다 크냐?
    -lt : less than, 왼쪽 변수가 오른쪽 변수보다 작냐?
    -ge : greater than or equal, 왼쪽 변수가 오른쪽 변수보다 크거나 같냐?
    -le : less than or equal, 왼쪽 변수가 오른쪽 변수보다 작거나 같냐?

    3.2.3 문자열의 비교

    문자열을 비교하기 위한 연산자는 다음과 같다.

    [ "String1" = "String2" ] : 두 문자열이 같은지
    [ "String1" != "String2" ] : 두 문자열이 다른지
    [ -z $X ] : $X라는 문자열 변수의 길이가 0이면 참
    [ -n $X ] : $X라는 문자열 변수의 길이가 0이 아닐 경우 참

    또한 '!'는 NOT을 나타낸다. 따라서 다음의 두 expression은 같은 것이다.

    [ -z $X ]
    [ ! -n $X ]

    3.2.4 File 검사

    이번 절에서는 File과 관련된 test를 알아보기로 한다. 파일이 존재하는지 검사하는 스크립트는 프로그램의 설정 파일을 검사할 때 많이 쓰인다. 예를 들어 $HOME/.vimrc가 있을 경우 $HOME/.vimrc 설정 파일을 읽어 들이고 없을 경우 default 설정 파일을 읽어 들이도록 하는데 사용될 수 있다.

    [ -b file ] : file이 존재하고 file이 block special file인 경우 참
    [ -c file ] : file이 존재하고 file이 character special file인 경우 참
    [ -d file ] : file이 존재하고 file이 directory인 경우 참
    [ -f file ] : file이 존재하고 file이 일반적인 file인 경우 참
    [ -g file ] : file이 존재하고 file에 Set-Group-Id가 set 되어 있는 경우 참
    [ -h file ] : file이 존재하고 file이 symbolic link인 경우 참
    [ -H file ] : file이 존재하고 file이 hidden directory인 경우 참
    [ -k file ] : file이 존재하고 file에 sticky bit가 set되어 있는 경우 참
    [ -p file ] : file이 존재하고 file이 named pipe인 경우 참
    [ -r file ] : file이 존재하고 file에 읽기 권한이 있는 경우 참
    [ -s file ] : file이 존재하고 file의 size가 0이 아닌 경우 참
    [ -u file ] : file이 존재하고 file에 Set-User-Id가 set되어 있는 경우 참
    [ -x file ] : file이 존재하고 file에 실행 권한이 있는 경우 참
    [ -w file ] : file이 존재하고 file에 쓰기 권한이 있는 경우 참

    위의 모든 것을 외울 필요는 없지만 쉘 스크립트에서 file과 관련하여 어떤 것을 검사할 수 있는지 정도는 알아두는 것이 좋다.

    3.2.5 AND/OR 연산자

    C 언어에서는 &&가 logical AND 연산자, ||가 logical OR 연산자인데, 본 쉘 프로그래밍에서는 AND는 -a, OR는 -o 이다.

    3.2.6 Loop

    본 쉘 프로그래밍에서는 C 언어와 비슷하게 3 개의 Loop 관련 문을 제공한다.

    3.2.6.1 for

    for문의 문법은 다음과 같다

    for VARIABLE in LIST
    do
    STATEMENT1
    STATEMENT2
    done

    1절에서 잠시 살펴 본 여러 file의 확장자를 동시에 바꾸는 스크립트를 다시 한 번 살펴보자

    #! /bin/sh

    X=`ls *.gif`
    for B in $X
    do
    temp=`basename $B .gif`
    mv $B $temp.jpg
    done

    X에 ls *.gif의 값이 저장된다. 이 값은 LIST의 형태로 생각하면 된다. 즉, 차례로 확장자가 gif인 파일이 저장된다고 생각하라.
    for B in $X를 살펴 보면, 앞의 ls *.gif의 결과 값 각각에 대해서 for 이하의 문을 실행하라는 것이 된다. 그리고 그 각각의 값은 임시로 B에 저장이 된다.

    temp=`basename $B .gif`

    basename은 $B에서 .gif 부분을 제외한 부분을 리턴하는 프로그램이다. 직접 프롬프트에서 명령을 내려서 결과를 확인할 수도 있다.

    23:17[wertyu@inos test]$ basename wertyu.gif .gif
    wertyu

    여기서 중요한 것은 '가 아니라 `이라는 점이다. 쉘 스크립트에서 변수의 값에 외부 명령을 실행 시킨 결과 값을 저장하기 위해서는 ` command `를 이용하면 된다. 즉

    temp=`basename $B .gif`

    는 $B에서 .gif 부분을 떼어버리고 남은 문자열을 temp에 저장하는 것이 된다. 나머지는 쉽게 이해할 수 있을 것이라 생각된다.

    다음의 스크립트는 grep과 비슷한 스크립트이다. (출처:http://pneuma.phys.ualberta.ca/~gingrich/research/shells/shells.html, 이 글에서 설명한 본 쉘 스크립트의 문법은 앞의 사이트에서 가져온 것도 몇 개 있으니 참고하기 바란다.)

    #! /bin/sh
    #
    # A script to look for the occurence of a string in a file
    # Usage: match [string] [file]
    #
    for word in `cat $2`
    do
    if [ ``$word'' = ``$1'' ]
    then
    echo ``Found $1 in file $2''
    else
    :
    fi
    done

    각자 이해해 보시길.... 근데, ``$word'' = ``$1'' 의 의미는 필자도 잘 모르겠다. 그냥 $word = $1으로 바꿔도 잘 돌아가던데....

    3.2.6.2 while

    for 문에 대해서는 이해가 되었을테니 이제 while 문을 볼까?

    문법)

    while condition
    do
    commands
    done

    예) 10, 9, 8,...,1을 출력하는 스크립트이다.

    number=10
    while [ $number -ge 1 ]
    do
    echo $number
    number=`expr $number - 1`
    done

    while은 condition이 참일 동안 loop를 돈다.

    3.2.6.3 until

    until은 while과 거의 비슷하다.

    문법)

    until condition
    do
    commands
    done

    단, while과 한 가지 차이점이 있는 것은 while은 condition이 참일 동안 loop를 돌지만, until은 condition이 거짓일 동안 loop를 돈다는 것이다.

    다음의 예는 while에서의 예와 같은 일을 하는 스크립트를 until을 이용하여 작성한 것이다.

    예)

    number=10
    until [ $number -lt 1 ]
    do
    echo $number
    number=`expr $number - 1`
    done

    3.2.7 case 문

    이 번 절에서는 case 문에 대해서 알아 보겠다. C 언의 case와 아주 유사하므로 쉽게 이해할 수 있을 것이다. 단, C 에서는 if-elseif를 쉽게 case 문으로 바꿀 수 있지만, 본 쉘 스크립트에서의 case는 if 보다 훨 씬 많은 기능을 제공한다.

    다음의 예를 보자.

    #!/bin/sh
    case $# in
    0)
    echo ""no parameters"";;
    1)
    echo "only one parameter." ;;
    *)
    echo "more than one parameter." ;;
    esac

    설명 안 해도 이제 이해되겟지? case 다음의 $#의 값에 따라서, 0)이냐 1)이냐에 따라서, 원하는 것을 실행 시킬 수 있다.
    위의 예에서는 case의 장점을 살펴 볼 수 없었다. 그러나 다음의 예를 보면, case의 유용함에 대해서 쉽게 알 수 있을 것이다. case의 유용함은 Regular Expression을 사용할 수 있다는 것이다. Regular Expression 까지 설명하려면 글이 길어 지므로, Regular Expression은 필자가 번역한 http://nnr.or.kr/linux/regular.htm을 참고하거나 다른 참고 자료를 살펴 보기 바란다.
    그럼 다음의 예를 보자

    while :
    do
    echo "Would you like to continue? c"
    read ANS
    case $ANS in
    [yY] | [yY][eE][sS]) echo "Fine, then we'll continue."
    break
    ;;
    [nN] | [nN][oO]) echo "We shall now stop."
    exit
    ;;
    *) echo "You must enter a yes or no verdict!"
    esac
    done
    echo "
    We are now out of the while loop."

    일단 저장해 놓고 실행 해 보자. 돌려 보면 알겠지만, Yes를 입력하든 Y를 입력하든 YES를 입력하든 yEs를 입력하든, [yY] | [yY][eE][sS])는 true가 된다.
    참 하나 설명을 안 하고 넘어간 부분이 있다.

    while :

    은 항상 참을 나타낸다.

    아. 또 read도 설명 안 했군. read ANS는 사용자로부터 문자열을 입력받아 ANS에 저장하는 명령이다.

    이 정도면 설명이 다 되었을 것이다.

    4. 마치면서

    아주 간단하게나마 본 쉘 프로그래밍에 대해서 알아 보았다. 너무나 간단하여 복잡한 일은 하기 힘들 것이다. 남은 것은 여러분의 노력 뿐... 아주 간단하게 본 쉘 스크립트를 알아 보았으므로, 다음 시간에는 TIP을 중심으로 본 쉘 스크립트에 대해서 알아 보겠다. 단, 필자도 아직 위의 내용 이외에는 아는 것이 별로 없으므로 공부를 한 후에 나머지 내용을 쓰도록 하겠다.

    * 참고 자료 :

    http://www.sao.nrc.ca/imsb/rcsg/documents/bourne/bourne.html
    http://pneuma.phys.ualberta.ca/~gingrich/research/shells/shells.html

    ps. 검색 엔진에서 shell programming이라고 입력하면 수 많은 결과가 나올테니 열심히 공부하기 바란다~~~


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


    출처 블로그 > Jay's
    원본 http://blog.naver.com/cocktail74/40004597832

    특수문자

    Match

    사용 예

    Match

    .

    임의의 한 문자

    *

    한 번도 없거나 한번 이상 반복

    abcd*

    abc, abcd, abcdd 등과 match

    .*

    모든 문자

    ^

    행의 처음

    ^X

    행의 첫머리의 X

    X^

    행의 임의의 위치의 X

    ^/^ or ^^

    행의 첫머리의 ^

    $

    행의 마지막

    X$

    행의 끝의 X

    $X

    행의 임의의 위치의 X

    \$$ or $$

    행의 끝의 $

    []

    [,] 안의 아무 문자

    c[aeiou]t

    cat, cet... 와 match

    -를 사용하여 범위 설정 가능

    c[a-z0-9]t

    두 번째 문자의 임의의 소문자나 숫자

    -와의 match를 위해선 [-나 -] 이용

    c[-ai]

    c-, ca, ci

    ]와의 match를 위해선 []와 같이 나타냄

    c[]ai]

    c], ca, ci

    ^를 [다음에 사용하면 [, ]안의 문자를 제외한 문자들과 match

    [A^-Z]

    대문자를 제외한 문자

    \{n,m\} (ed, sed, grep 에서만 사용 가능)

    \{n\}은 바로 앞의 expression이 n번 반복 된 것

    [0-9]\{3\}

    세 개의 숫자

    \{n,\}은 바로 앞의 expression이 n번 또는 그 이상 반복된 것

    0\{4,\}

    4개 이상의 0

    \{n,m\}는 바로 앞의 expression이 n번에서 m번 반복된 것

    1\{4,9\}

    4개에서 5개의 1

    \

    특수 문자들의 기능을 수행하지 않고 문자 그대로 받아들임

    \*\**

    한 개 또는 그 이상의 *

    ^[ ^I]*$

    공백행과 space나 TAB을 포함한 행(겉보기 공백행). 여기서 ^I는 ctrl+I로써 TAB과 같다

    ^.*$

    임의의 행 전체

    modifier를 이용하여 변수 값이나 history에 저장된 명령어의 내용을 변환시킬 수 있다.

    (단, set A = (/home/user/temp.c), set B = (a.c b.c c.c d.c))

    Modifier

    기능

    사용 예

    결과

    :h

    pathname에서 마지막 부분을 제어하고 앞부분만 남김

    echo $A:h

    /home/user

    :t

    pathname에서 마지막 부분만 남기고 pathname을 제거함

    echo $A:t

    temp.c

    :r

    pathname에서 끝 부분의 .xxx만 제거

    echo $A:r

    /home/user/temp

    :e

    .xxx만 남기고 앞부분 제거

    echo $A:e

    c

    :g

    :gh, :gr, :gt, :ge의 형태로 사용되며, array변수에 저장된 모든 값들에 h,r,t,e를 적용시킨다.

    echo $B:r

    a b c d

    :p

    명령어를 실행시키지 않고 출력만 시킨다.

    !:p

    :q

    특수 문자들의 기능을 수행하지 않고 단순히 출력만 시킨다.

    %echo *
    %!:q

    *

    특수문자

    의미

    비고

    !

    history 기능을 시작하기 위한 특수문자

    !n

    n번째로 사용된 명령 실행

    !-n

    현재부터 n번째 앞에 사용된 명령 실행

    !!

    바로 전에 실행되었던 명령 실행

    !-1

    !string

    가장 최근에 string으로 시작되는 명령 실행

    !?string[?]

    가장 최근에 string을 포함하고 있는 명령 실행

    ^aa^bb

    마지막으로 실행된 명령어에서 aa를 bb로 치환하여 명령 실행

    !*

    마지막으로 실행된 명령에 사용된 모든 argument

    !$ or !!$

    마지막 명령의 마지막 argument

    !^

    마지막 명령의 첫 argument

    event:s^aa^bb

    event는 앞에서 !로 시작하는 history 명령이다. aa를 bb로 치환한다. 단, ^대신 다른 특수 문자를 사용하여도 된다.

    ex) !23:s/aa/bb

    !:n or !!:n

    마지막 명령의 n번째 argument

    !:n*

    마지막 명령의 n번째부터 그 이후의 argument

    !:n-$

    !:0

    마지막 명령의 명령어만 나타냄

    !:n-m

    마지막 명령의 n번째부터 m번째까지의 argument

    !:-n

    마지막 명령의 명령어부터 n번째 argument까지

    !:n-

    마지막 명령의 n번째부터 마지막 argument를 제외한 argument

    !?string?%

    가장 최근에 string을 포함하고 있는 단어를 나타냄

    색코드

    의미

    0

    기본 화면색. 흰 글자색. 검정 배경색

    1

    bold intensity

    4

    흑백 모드에서는 밑줄

    5

    반짝임

    7

    역상

    30

    검정 (회색) 글자색

    31

    빨강 (옅은 빨강) 글자색

    32

    녹색 (옅은 녹색) 글자색

    33

    갈색 (노랑) 글자색

    34

    파랑 (옅은 파랑) 글자색

    35

    보라 (옅은 보라) 글자색

    36

    cyan (옅은 cyan) 글자색

    37

    흰색 (밝은 흰색) 글자색

    40

    검정 (회색) 배경색

    41

    빨강 (옅은 빨강) 배경색

    42

    녹색 (옅은 녹색) 배경색

    43

    갈색 (노랑) 배경색

    44

    파랑 (옅은 파랑) 배경색

    45

    보라 (옅은 보라) 배경색

    46

    cyan (옅은 cyan) 배경색

    47

    흰색 (밝은 흰색) 배경색

    10

    기본 font 선택

    38

    밑줄 사용 가능

    39

    밑줄 사용 불가능

    Escape Sequence

    기능

    ESCc

    화면을 지우고 커서를 1행 1열로 이동시킴

    ESC[nA

    커서를 현위치에서 위로 n칸 이동

    ESC[nB

    커서를 현위치에서 아래로 n칸 이동

    ESC[nC

    커서를 현위치에서 오른쪽으로 n칸 이동

    ESC[nD

    커서를 현위치에서 왼족으로 n칸 이동

    ESC[n;mH 또는 ESC[n;mf

    커서를 m열 n행으로 이동시킴

    ESC[nJ

    n = 0 이면 현위치에서 화면의 끝까지 지움
    n = 1 이면 화면의 처음에서 현위치까지 지움
    n = 2 이면 화면 전체를 지움

    ESC[nK

    n = 0 이면 현재 커서의 위치에서 행의 끝까지 지움
    n = 1 이면 행의 처음에서 현재의 커서 위치까지 지움
    n = 2 이면 현재 커서가 있는 행을 모두 지움

    ESC[nL

    n 행을 현재 커서 위치에 삽입

    ESC[nM

    현재 커서 위치에서부터 n행 삭제

    ESC[nP

    현재 커서 위치의 행의 처음부터 n개 문자 삭제

    ESC[nX

    현재 커서 위치에서부터 n개 문자 삭제

    ESC[nM

    화면의 색지정. 여러 가지 색을 지정할 때는 ;를 사용하여 구분한다.

    2006/09/08 23:12 2006/09/08 23:12
    이 글에는 트랙백을 보낼 수 없습니다
    출처 블로그 > 막강 파워 스킬만이 살길이다~
    원본 http://blog.naver.com/norther80/80010287760


    작성자 : 김칠봉
    작성일 : 2001.03.12

    목차
    1. 가장 일반적인 find 명령어

    2. find 명령어 일반적인 옵션
    2-1. 사용법 개요
    2-2. 일반적으로 표현식 옵션 구분
    3-3. 자주 사용되는 표현식 옵션
    3-4. path(find 명령어 다음의 path)
    3-5. 표현식-연산자

    3. 예제
    3-1. 다른 명령어와 결합형태(ls,xargs)
    3-2. 퍼미션 관련 예제
    3-3. 유저와 관련된 예제
    3-4. 팁
    - 최근 하루(1) 동안(-)에 변경(change)된 파일을 찾을려면(-ctime)?
    - 오래된 파일을 찾을려면(30일 이상 수정(modify))되지 않은)?
    - 최근 30일(30) 안에(-) 접근(access)하지 않은 파일과 디렉토리를 리스트로 만들려면(-atime)?
    - 자신의 홈디렉토리에서 만 검색하려면?
    - 서브 디렉토리로 내려가지 않고 현재 디렉토리에서만 검색하려면?
    - 특정 유저(foobar) 소유의 파일을 찾을려면?
    - 퍼미션이 777인 파일을 찾을려면 ?
    - others에게 쓰기 권한이 있는 파일을 찾을려면?
    - others에게 쓰기 권한이 있는 파일을 찾아 쓰기 권한을 없애려면?
    - 유저이름과 그룹이름이 없는 파일을 찾을려면?
    - 빈 파일을 찾을려면?
    - 파일크기가 100M 이상된 파일을 찾을려면?
    - *.bak 파일을 찾아 지울려면?
    - *.bak 파일을 찾아 특정 디렉토리로 옮길려면?
    - 디렉토리 만 찾을려면?
    - root권한으로 실행되는 파일을 찾을려면?
    - 다른 파일시스템을 검색하지 않을려면?
    - 파일이름에 공백이 들어간 파일을 찾을려면?
    - 숨겨진(hidden) 파일을 찾을려면?
    - 같은 이름을 가진 디렉토리를 찾을려면?
    - 잘못된 링크를 찾을려면?

    4. find 명령어에 대해서 좀더 알아보려면?

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

    1. 가장 일반적인 find 명령어

    # find /path -name "foobar" -print

    제일 먼저(?) 배우는 형식이 아닌가 쉽군요.


    2. find 명령어 일반적인 옵션

    2-1. 사용법 개요

    find 명령어 사용법 보기 :

    # find --help
    # man find (직접 입력해 보세요. 내용이 너무 많아서..)

    사용법 : find [path...] [expression]
    기본값 : default path는 현재 디렉토리; default expression은 -print

    표현식(expression) 구성 :
    operators (decreasing precedence; -and is implicit where no others are given):
    ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2
    EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2
    options (always true): -daystart -depth -follow --help
    -maxdepth LEVELS -mindepth LEVELS -mount -noleaf --version -xdev
    tests (N can be +N or -N or N):
    -amin N -anewer FILE -atime N -cmin N
    -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME
    -ilname PATTERN -iname PATTERN -inum N -ipath PATTERN -iregex PATTERN
    -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE
    -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN
    -size N[bckw] -true -type [bcdpfls] -uid N -used N -user NAME
    -xtype [bcdpfls]
    actions:
    -exec COMMAND ; -fprint FILE -fprint0 FILE -fprintf FILE FORMAT
    -ok COMMAND ; -print -print0 -printf FORMAT -prune -ls

    간단하게 몇가지만 알아보죠...
    (자세한 사용설명은 꼭 man 페이지를 읽어보세요....한글은 없군요..T.T)


    2-2. 일반적으로 표현식 옵션 구분

    -a'xxxx'
    'xxxx'에 대한 Access(접근)
    -c'xxxx'
    'xxxx'에 대한 Changes(변경), 마지막으로 Access한 경우 변경됨
    -m'xxxx'
    'xxxx'에 대한 Modify(수정), 파일내용 자체 수정한 경우
    -i'xxxx'
    'xxxx'(inum 제외)에 대한 Insensitive(대소문자 구분없이)

    3-3. 자주 사용되는 표현식 옵션

    N
    정확하게 N과 일치
    +N
    N 보다 큰 경우
    -N
    N 보다 작은 경우
    -name PATTERN
    PATTERN에 일치하는 파일 찾기, 와일드카드 문자 사용가능
    -iname PATTERN
    PATTERN에 일치하지 않은(insensitive) 파일 찾기
    -perm [+-]mode
    PERMission('mode')에 해당되는 파일 찾기, ls와 결합 가능
    -type [bcdpfls]
    b(블럭파일), c(특정 문자), d(디렉토리), p(파이프),
    f(정규표현 일반파일), l(링크), s(소켓) 유형의 파일 찾기
    -size N[bckw]
    파일 크기가 N 인 파일 찾기
    b(블럭-기본값), c(bytes), k(kbytes),
    w(2바이트 단어)
    -user NAME
    NAME은 유저이름이거나 UID
    -atime N
    N*24 시간 동안에 Access 한 파일
    -ctime N
    N*24 시간 동안에 Changes 한 파일(내용수정이 아니고 읽기모드도 Changes됨)
    -mtime N
    N*24 시간 동안에 Modify 한 파일
    -empty
    파일이 비어 있고(0 bytes), 정규식 파일이거나 디렉토리
    -newer FILE
    FILE 보다 최근에 갱신된 파일
    -path PATTERN
    path가 PATTERN과 일치하는 path에 대해서 검색
    -regex PATTERN
    파일이름이 PATTERN에 일치하는 정규식에 대해서 검색
    -inum N
    inode N을 갖는 파일
    -nouser,-nogroup
    USER나 GROUP에 이름이 없는 파일 검색(UID,GID만 있는 파일)
    -exec COMMAND
    검색된 파일을 찾으면 COMMAND 명령을 실행한다.
    COMMAND 인자(검색된 파일)는 {}으로 사용하며,
    이때 COMMAND 끝은 ;(;이 아님)을 사용해야 한다. 즉 명령구분
    문자인 ';'을 탈출()시켜줘야 한다.
    -ok COMMAND
    -exec COMMAND와 같지만 COMMAND를 실행하기 전에 확인을 요청한다.

    3-4. path(find 명령어 다음의 path)
    .
    현재 디렉토리(기본값이므로 생략해도 됨)
    `pwd`
    현재 디렉토리와 결합(?) `은 ~문자가 있는 자판
    $(pwd)
    위의 `pwd`와 같거나 비슷함
    /
    최상위 루트 디렉토리에서 하위 모든 디렉토리
    /home
    특정 /home 디렉토리에서 하위 모든 디렉토리
    /{usr,home/{aaa,san2},var}
    /usr, /usr/home/aaa /usr/home/san2 /var

    3-5. 표현식-연산자

    ( 표현식 )
    '표현식'을 우선적으로 먼저 수행
    (와 )앞에 를 넣어야 하며, '표현식'과 공백을 각각 둔다.
    ( A + B ) * ( C + D ) 와 같이 (, )안을 우선적으로 수행
    ! 표현식 , -not 표현식
    '표현식'을 부정
    표현식1 -a 표현식2, 표현식1 -and 표현식2
    표현식1과 표현식2의 AND 연산
    표현식1 -o 표현식2, 표현식1 -or 표현식2
    표현식1과 표현식2의 OR 연산


    3. 예제

    3-1. 다른 명령어와 결합 형태(ls,xargs)

    찾는 것 그 차체 만으로 만족(?) 할 수 도 있지만 그 결과에 대해서
    어떤 행동(Actions)을 취할 필요가 있습니다.

    형태1. -exec 이용시

    # find ..... -exec COMMAND {} ;

    형태2. xargs 명령어로 표준 입력받아 COMMAND 수행

    # find ..... | xargs COMMAND

    형태3. ls 명령어로 최종 결과 출력

    # ls -l `find .....[COMMAND]`
    또는
    # find .... ls
    (ls는 ls -dils와 같음)

    xargs
    xargs rpm 정보보기
    # rpm -qi `rpm -qf $(which xargs)`
    또는
    # rpm -qf `which xargs` | xargs rpm -qi

    즉, find 결과에 대해서,

    형태1은 -exec를 사용하여 그 인자를 {}로 사용하고,

    형태2는 xargs 명령어로 find에서 넘어온 결과(표준출력)에 대해서 COMMAND를 실행하고,

    형태3은 오른쪽의 find 결과물에 대해서 ls 명령어를 실행합니다.
    간혹 '/bin/ls Argument list too long'이라는 에러를 낸 경우도 있습니다.
    이는 검색조건에 너무 많은 와일드카드 문자로 찾을 경우에 그렇습니다.
    이를 테면 /*/*/*.*/.*,

    `은 ~문자가 있는 자판(역인용부호).

    ls -l 명령어를 사용할 경우, 찾는 결과가 없다면 모두 출력됩니다.
    (ls -l와 같기 때문에)
    ls 명령어와 마찬가지로 다른 명령어(chmod, chmod)를 결합하여 사용할 경우 그 찾는
    결과가 없다면 명령어에 대한 에러를 내겠죠.
    (chmod 'null')과 같은 예..........

    # find /{home,usr/{src,local/src}} -nouser -o -nogroup -exec ls -l {} ; -print | more
    # find /{home,usr/{src,local/src}} -nouser -o -nogroup -print | xargs ls -l | more

    위의 2개의 명령어 대해서 직접 테스트 해보세요...

    전자의 경우, 아마 아무것도 출력되지 않을 겁니다.

    # find /{home,usr/{src,local/src}} ( -nouser -o -nogroup ) -exec ls -l {} ; -print | more

    위와 같이 해야 맞겠죠...(우선순위)

    후자의 경우도 마찬가지로 다음과 같이 우선순위를 정해놓아야 겠지요..
    아마 원하는 출력이 이 경우일 것 같군요.

    # find /{home,usr/{src,local/src}} ( -nouser -o -nogroup ) -print | xargs ls -l | more


    3-2. 퍼미션 관련 예제

    othesrs에 쓰기(w:2) 권한이 있는 모든(-기호를 붙임) 파일 리스트를 찾을려면?

    # find `pwd` -perm -2 -print | xargs ls -l

    여기에서 2는
    퍼미션이 -------w- 와 일치하는 파일이며 -의 의미는 rwx-중 하나.

    왜 2인가요?
    만약 퍼미션이 755 이라면,

    700 : rwx------ : user
    50 : ---r-x--- : group
    5 : ------r-x : others
    ------------------------
    755 : rwxr-xr-x : others는 읽기와 실행 권한

    따라서 others의 권한은 8진수로 5(r+x)이다.

    그렇다면, others가 쓰기(w:2) 권한은 당연히 -------w-

    그룹이나 others에게 쓰기 권한이 있는 파일일 경우

    -perm -20 -o -perm -2

    그룹과 others에게 모두 쓰기 권한이 있는 파일일 경우

    -perm -22

    [others에게 w 권한이 있는 파일에 w 권한 없애기]

    방법1)
    1. others에게 w 권한이 있는 파일 리스트 출력

    # find `pwd` -perm -2 -print | xargs ls -l | more
    (만약 매치되는 리스트가 없다면 전부 출력함)

    2. others에게 w 권한을 없애기

    # find `pwd` -perm -2 -print | xargs chmod o-w
    (만약 매치되는 리스트가 없다면 chmod에 에러를 냄)

    방법2) 방법1)의 과정을 한꺼번에 할 경우

    # find `pwd` -perm -2 -exec chmod o-w {} ; -print | xargs ls -l
    또는
    # ls -l `find $(pwd) -perm -2 -print | xargs chmod o-rwx` | more

    이 경우는 퍼미션이 조정된 결과를 출력함.


    3-3. 유저와 관련된 예제

    UID와 GID에 대한 유저가 없는 파일을 root.root로 바꾸어 보죠.

    1) 먼저 리스트를 출력해 보자.(확인해야하니깐)

    # find . ( -nouser -o -nogroup ) -print | xargs ls -l | more

    2) 확인했으면, chown root.root 명령을 내리자.

    # find . ( -nouser -o -nogroup ) -print | xargs chown root.root | more
    또는
    # find . ( -nouser -o -nogroup ) -exec chown root.root {} ; -print | xargs ls -l
    (chown root.root 의 결과를 ls -l)


    3-4. 유용한 팁

    *주의) ***********************************************
    -a'xxxx'
    'xxxx'에 대한 Access(접근), 읽기
    -c'xxxx'
    'xxxx'에 대한 Changes(변경), 마지막으로 Access한 경우에도 변경됨
    -m'xxxx'
    'xxxx'에 대한 Modify(수정), 파일내용 자체 수정한 경우
    *****************************************************

    - 최근 하루(1) 동안(-)에 변경(change)된 파일을 찾을려면(-ctime)?

    # find / -ctime -1 -a -type f | xargs ls -l | more

    - 오래된 파일을 찾을려면(30일 이상 수정(modify))되지 않은)?

    # find / -mtime +30 -print | more

    - 최근 30일(30) 안에(-) 접근(access)하지 않은 파일과 디렉토리를 리스트로 만들려면(-atime)?

    # find / ! ( -atime -30 -a ( -type d -o -type f ) ) | xargs ls -l > not_access.list

    - 자신의 홈디렉토리에서 만 검색하려면?

    # find $HOM ...
    또는
    # find ~root ...

    - 서브 디렉토리로 내려가지 않고 현재 디렉토리에서만 검색하려면?

    # find . -prune ...

    - 특정 유저(foobar) 소유의 파일을 찾을려면?

    # find / -user foobar -print | more

    - 퍼미션이 777인 파일을 찾을려면 ?

    # find / -perm 777 -print | xargs ls -l | more

    - others에게 쓰기 권한이 있는 파일을 찾을려면?

    # find / -perm -2 -print | xargs ls -l | more

    - others에게 쓰기 권한이 있는 파일을 찾아 쓰기 권한을 없애려면?

    # find / -perm -2 -print | xargs chmod o-w
    또는
    # find / -perm -2 -exec chmod o-w {} ; -print | xargs ls -l | more

    - 유저이름과 그룹이름이 없는 파일을 찾을려면?

    # find / ( -nouser -o -nogroup ) -print | more

    - 빈 파일을 찾을려면?

    # find / -empty -print | more
    또는
    # find / -size 0 -print | more

    - 파일크기가 100M 이상된 파일을 찾을려면?

    # find / -size +102400k -print | xargs ls -hl

    - *.bak 파일을 찾아 지울려면?

    # find / -name "*.bak" -exec rm -rf {} ;

    - *.bak 파일을 찾아 특정 디렉토리로 옮길려면?

    # mv `find . -name "*.bak"` /home/bak/

    - 디렉토리 만 찾을려면?

    # find . -type d ...

    - root권한으로 실행되는 파일을 찾을려면?

    # find / ( -user root -a -perm +4000 ) -print | xargs ls -l | more

    - 다른 파일시스템을 검색하지 않을려면?

    # find / -xdev ...

    - 파일이름에 공백이 들어간 파일을 찾을려면?

    # find / -name "* *" -print

    - 숨겨진(hidden) 파일을 찾을려면?

    # find / -name ".*" -print | more

    - 같은 이름을 가진 디렉토리를 찾을려면?

    # find / -type d -print | awk -F/ '{printf("%st%sn",$NF,$0);}' | sort| more
    *주)'O'Reilly Unix Power Tools' 참고

    - 잘못된 링크를 찾을려면?

    # find . -type l -print | perl -nle '-e || print' | xargs ls -l
    *주)'O'Reilly Unix Power Tools' 참고
    2006/09/08 23:11 2006/09/08 23:11
    이 글에는 트랙백을 보낼 수 없습니다
    웅쓰:웅자의 상상플러스
    웅자의 상상플러스
    전체 (379)
    게임 (5)
    영화 (2)
    기타 (23)
    맛집 (5)
    영어 (2)
    대수학 (3)
    형태소 (5)
    Hacking (9)
    Linux (112)
    HTML (48)
    Application_developing (48)
    Web_developing (102)
    Window (11)
    «   2006/09   »
              1 2
    3 4 5 6 7 8 9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30
    1. 2016/01 (1)
    2. 2015/12 (3)
    3. 2015/10 (3)
    4. 2015/03 (2)
    5. 2015/01 (4)