반응형

The Zip format is also used in the JAR (Java ARchive) file format, which is a way to collect a group of files into a single compressed file, just like Zip. However, like everything else in Java, JAR files are cross-platform, so you don’t need to worry about platform issues. You can also include audio and image files as well as class files.

JAR files are particularly helpful when you deal with the Internet. Before JAR files, your Web browser would have to make repeated requests of a Web server in order to download all of the files that make up an applet. In addition, each of these files was uncompressed. By combining all of the files for a particular applet into a single JAR file, only one server request is necessary and the transfer is faster because of compression. And each entry in a JAR file can be digitally signed for security (see Chapter 14 for an example of signing).

A JAR file consists of a single file containing a collection of zipped files along with a “manifest” that describes them. (You can create your own manifest file; otherwise, the jar program will do it for you.) You can find out more about JAR manifests in the JDK documentation.

The jar utility that comes with Sun’s JDK automatically compresses the files of your choice. You invoke it on the command line:

jar [options] destination [manifest] inputfile(s)


The options are simply a collection of letters (no hyphen or any other indicator is necessary). Unix/Linux users will note the similarity to the tar options. These are:

c

Creates a new or empty archive.

t

Lists the table of contents.

x

Extracts all files.

x file

Extracts the named file.

f

Says: “I’m going to give you the name of the file.” If you don’t use this, jar assumes that its input will come from standard input, or, if it is creating a file, its output will go to standard output.

m

Says that the first argument will be the name of the user-created manifest file.

v

Generates verbose output describing what jar is doing.

0

Only store the files; doesn’t compress the files (use to create a JAR file that you can put in your classpath).

M

Don’t automatically create a manifest file.

If a subdirectory is included in the files to be put into the JAR file, that subdirectory is automatically added, including all of its subdirectories, etc. Path information is also preserved.

Here are some typical ways to invoke jar:

jar cf myJarFile.jar *.class


This creates a JAR file called myJarFile.jar that contains all of the class files in the current directory, along with an automatically generated manifest file.

jar cmf myJarFile.jar myManifestFile.mf *.class


Like the previous example, but adding a user-created manifest file called myManifestFile.mf.

jar tf myJarFile.jar


Produces a table of contents of the files in myJarFile.jar.

jar tvf myJarFile.jar


Adds the “verbose” flag to give more detailed information about the files in myJarFile.jar.

jar cvf myApp.jar audio classes image


Assuming audio, classes, and image are subdirectories, this combines all of the subdirectories into the file myApp.jar. The “verbose” flag is also included to give extra feedback while the jar program is working.

If you create a JAR file using the 0 (zero) option, that file can be placed in your CLASSPATH:

CLASSPATH="lib1.jar;lib2.jar;"


Then Java can search lib1.jar and lib2.jar for class files.

The jar tool isn’t as useful as a zip utility. For example, you can’t add or update files to an existing JAR file; you can create JAR files only from scratch. Also, you can’t move files into a JAR file, erasing them as they are moved. However, a JAR file created on one platform will be transparently readable by the jar tool on any other platform (a problem that sometimes plagues zip utilities).

As you will see in Chapter 14, JAR files are also used to package JavaBeans.

출처 : http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ314_034.htm

반응형
반응형

################################################################
1. Backup 하기

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



1.
백업 가능대상
 

 - database (all datafile 과 현재 control file)
 - tablespace
 - datafile (current 또는 image copy)
 - archived redo log
 - control file (current 또는 image copy)
   
* 백업이 되는 않는 대상( init.ora, password file. listener.ora, tnsnames.ora, BFILES)

 

2. 백업 분류 

 - consistent vs Inconsistent 백업

     RMAN을 통한 백업은 대상 DB open 혹은 close된 시점에서 백업이 가능하며, open 상태에서의 백업은 항상 Inconsistent 이며, consistent 백업은 항상 mount상태에서 백업을 받은 것을 말하며 이전에 DB crash되거나 비 정상 종료가 되지 않아야 한다.

     ( NOARCHIVE MODE에서는 INCONSISTENT 백업을 허용하지 않는다)  


3.
백업 방법
3.1 전체 database 백업 

 run {

        allocate channel c1 device type disk;

        backup database

        format ‘/data/backup/rman/%d_%p_%t’;

  }

 
3.2 tablespace 백업

 run {

       allocate channel c1 device type disk;

       allocate channel c2 device type disk;

       allocate channel c3 device type disk;

       backup filesperset=3                                  ## 한 백업set datafile 3개를 넘어서 백업받지 않는 조건

       tablespace example , users,system

       include current controlfile;                          ## 현재 control file도 같이 백업

 }


3.3 datafile
백업

 run {

       allocate channel c1 device type disk;

       backup  datafile 1, 2, 3, 4, 5, 6 ;

 }

 
3.4 datafile copy

 run {

        allocate channel c1 device type disk;   

        backup datafilecopy ‘/home/oracle/oradata/testdb/users01.dbf’

        format ‘/data/backup/rman/users01.bak’;

 }

 
3.5 current control file 백업

 run {

       allocate channel ch1 type disk;

       backup current controlfile

       tag = mondayPMbackup;

  }

 
3.6 다른 object 백업시 control file 백업 추가 방법

 run {

       allocate channel ch1 type disk;

       backup tablespace users

       include current controlfile;                          ## users 라는 tablespace 백업시 currnet control file 포함

 }

 
3.7 Archive redo log 백업

 

 run {

       allocate channel ch1 type disk;

       backup archivelog all                                 ## archive된 모든 redo log 백업

       delete input;                                               ## 백업받은 archive log 삭제

 }

 

 * archived redo log 백업시 time, SCN, log sequence number 조건을 사용해서 백업 받을수 있다.

    예) time 조건

 run {

        allocate channel ch1 type disk;

        backup archivelog

        from time ‘SYSDATE-2’ until time ‘SYSDATE-1’;         ## 2일전부터 1일전까지 발생한 archived redolog

 }                                                                                              

 

4. incremental 백업

 

 run {

       allocate channel ch1 type disk;

       backup incremental level=0                        ## level 0 으로 database incremental backup

       database;

 }

 

 run {

       allocate channel ch1 type disk;

       backup incremental level=1                        ## level 1 system tablespace sale.f datafile 을 백업

       tablespace system                                     ##   하는데 level 0 또는 1이후로 변경된 사항만

       datafile ‘/home/oracle/oradata/testdb/example01.dbf’;   ##                     백업받는다.

 }

 

 run {

       allocate channel ch1 type disk;

       backup incremental level=2 cumulative       ## level 2 tbs_1 tablespace 백업하는데 level 0 또는 1

       tablespace  example;                                 ## 이후로 변경된 사항만 백업(cumulative 옵션사용)

 }

 

 

5. image copies

 

1. datafile

2. archived redo log

3. control file

 
5.1 datafile controlfile image copy

1)

 run {

       allocate channel ch1 type disk;

       copy

       datafile 1 to ‘/data/backup/rman/df_1.bak,

       datafile 2 to ‘/data/backup/rman/df_2.bak’,

       datafile 3 to ‘/data/backup/rman/df_3.bak’,

       datafile 4 to ‘/data/backup/rman/df_4.bak’,

       current controlfile to ‘/data/backup/rman/control.bak;

 }

 

  

################################################################
Restore

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

 

1. Restore Datafile, Controlfile, Archived redo log file

 - restore 명령으로 백업set이나 image copy본에서 restore가능하다.

 (image copy본은 disk에서만 가능)

 

2. restore database

 - database restore시에는 db는 항상 close상태이어야 한다. (db open된 상태라면 아래와 같이 shutdown , startup mount 상태로 한다.)

 

     shutdown immediate

     startup mount

 

ex) 기존의 datafile 위치에 database restore 하는경우

 run {

       allocate channel ch1 type disk;

       allocate channel ch2 type disk;

       allocate channel ch2 type disk;

       restore database;

 }

 

3. tablespace datafile restore
3.1 기존위치에 tablespace restore

 run {

        sql ‘alter tablespace example offline ’;

        allocate channel ch1 type disk;

        restore tablespace  example;

 }

 
3.2 새로운 위치에 tablespace restore

 run {

        allocate channel ch1 type disk;

        sql ‘alter tablespace  example offline’ ;

         ## 새로운 위치에 datafile restore

         set newname for datafile ‘/home/oracle/oradata/testdb/example01.dbf’
          
to ‘/home/oracle/temp/example01.dbf’;

         restore tablespace example;

         ## 변경된 위치로 control file이 인식할 수 있게 함

         switch datafile all;

 }


4. control file restore

 - nomount 단계에서 restore 해야함

 run {

       allocate channel ch1 type disk;

       restore controlfile;

       alter database mount;

 }

 

5. Archived redo log restore

 - mount 단계에서 restore

 run {

       ## init.ora 에 명시되어있는 log_archive_dest 위치가 아니 다른 위치에 restore하고자 할때

       set archivelog destination to ‘/oracle/temp_restore’;

       allocate channel ch1 type disk;

       restore archivelog all;

 }

  

################################################################
Recovery

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

1. Complete Recovery
1.1 recover database

 shutdown immediate;

 startup mount;

 

 run {

       allocate channel ch1 type disk;

       restore database;

       recover database;

 }

 
1.2 recover database (control file 백업본을 restore하고 복구하는 경우)

 startup nomount;

 

 run {

        allocate channel ch1 type ‘sbt_tape’;

        restore controlfile;

        alter database mount;

        restore database;

        recover database;

        alter database open resetlogs;

 }

 * resetlogs database open한 경우 reset database명령수행이 필요하며, 다시 database를 백업받는다.

 
1.3. recover tablespace
1.3.1 database close상태이고 tablespace위치에 접근가능할 때

 run {

        allocate channel ch1 type disk;

        restore tablespace tbs_3;

        recover tablespace tbs_3;

 }

 
1.3.2 database close상태이고 tablespace위치에 접근가능하지 못할 때
(datafile 위치를 바꿀 필요가 있을때)

 run {

        allocate channel ch1 type disk;

        set newname for datafile ‘/disk1/oracle/tbs_1.f’ to ‘/disk2/oracle/tbs_1.f’;

        restore tablespace tbs_1;

        switch datafile all;

        recover tablespace tbs_1;

 }

 
1.3.3 database open된 상태이고 tablespace위치에 접근가능할 때

 run {

        sql ‘alter tablespace user_data offline temporary’;

        allocate channel ch1 type disk;

        set archivelog destination to ‘/oracle/temp/arc1_restore’;

        restore tablespace user_data;

        recover tablespace user_data;

        sql ‘alter tablespace user_data online’;

 }


1.3.4 database
open된 상태이고 tablespace위치에 접근불가능할 때

 run {

        sql ‘alter tablespace tbs_1 offline temporary’;

        allocate channel ch1 type disk;

        set newname for datafile ‘/disk1/oracle/tbs_1.f’ to ‘/disk2/oracle/tbs_2.f’;

        restore tablespace tbs_1;

        switch datafile all;

        recover tablespace tbs_1;

        sql ‘alter tablespace tbs_1 online’;

 }


2. Incomplete Recovery
2.1 time base Incomplete Recovery

   time base Incomplete Recovery를 하고자 할 때는 time format을 확인한 후 작업해야 한다.

  (필요시 time format설정 변경)

 

   ) NLS_LANG=american

   NLS_DATE_FORMAT=’Mon DD YYYY HH24:MI:SS’

 

   database open시는 반드시 shutdown후 작업

     shutdown immediate;

     startup mount;

 

 run {

       set until time ‘Nov 15 1998 09:00:00’;

       allocate channel ch1 type ‘sbt_tape’;

       restore database;

       recover databse;

       alter database open resetlogs;

 }

 

   resetlogs database open후 반드시 recovery catalog database reset database 명령으로 초기화 후 target database를 백업 받도록 한다.

 


2.2
특정 SCN까지 recovery

 database open시는 반드시 shutdown후 작업

   shutdown immediate;

   startup mount;

 

 run {

       set until scn 1000;

       allocate channel ch1 type ‘sbt_tape’;

       restore database;

       recover database;

       alter database open resetlogs;

 }

 

   resetlogs database open후 반드시 recovery catalog database reset database 명령으로 초기화 후 target database를 백업 받도록 한다.

 


2.3
특정 log sequence까지 recovery

  어느시점까지 recovery할것인지는 v$log_history view 조회를 통해서 결정

 

   database open시는 반드시 shutdown후 작업

    shutdown immediate;

    startup mount;

 

 ## thread 1에 대해 log sequence 6 까지 recovery하는 예

 run {

       set until logseq 6 on thread 1;

       allocate channel ch1 type ‘sbt_tape’;

       restore database;

       recover database;

       alter database open resetlogs;

 }

  resetlogs database open후 반드시 recovery catalog database reset database 명령으로 초기화 후 target database를 백업 받도록 한다.


3.  recovery catalog
없이 DBPITR(DataBase Point In Time Recovery)할때

 - recovery catalog 없이 DBPITR 수행을 하고자 할때는 아래와 같은 몇가지 필요한 사항들이 있다

 - control file은 별도로 백업을 받아 두도록 한다.

    database 백업시 control file도 자동으로 백업을 받아지기는 하지만 그때 발생한 database 백업에 대한 정보를 가지고 있지 못하기 때문에 별도로 아래와 같이 백업을 받도록 한다.

 

     backup database;

    backup current controlfile tag = ‘database backup’;

 

    controlfile 백업시 tag 옵션을 사용하여 향후에 특정시점에 백업받은 controlfile을 사용할 수 있도록 한다.

 - tablespace 변경 시나 datafile 추가시 백업을 수행하도록 한다.(control file도 포함)

 

 예)

     catalog없이 rman 시작

     rman target / nocatalog

 

     만일 database open된 상태라면 shutdown mount시킨다.

     startup force mount;

 

     특정 임시위치에 control file restore

 run {

        set until time ‘Jun 18 1998 16:32:36’;

        allocate channel ch1 type disk;

        restore controlfile to ‘/tmp/cf.tmp’ from tag = ‘database backup’;

 }

 

 백업받은 특정 controlfile restore할 수 없을 때는 rman을 통해 restore받은 controlfile아래와 같은 sql 명령으로 백업받은 후 init.ora 관련 파라미터를 조정한후 다음단계를 수행하도록 한다.


 - sql > alter database backup controlfile to ‘/tmp/original_cf’;

 - database shutdown

 - init.ora 에 명시된 CONTROL_FILES 파라미터를 적절히 조정

 - 백업받은 controlfile을 적당한 위치에 copy

 - startup mount

 run {

        set until time ‘Jun 18 1998 16:32:36’;

        allocate channel ch1 type disk;

        restore database;

        recover database noredo;                         ## database Noarchive Mode일때 noredo 옵션사용

        alter database open resetlogs;                  ## Archive Mode일때는 noredo 옵션없이 recover한다.

 }


출처 : cafe.naver.com/prodba
반응형

'Database > ORACLE' 카테고리의 다른 글

오라클 클론 디비로 복구 하기  (0) 2010.07.13
PL/SQL Exception  (0) 2010.07.06
오라클 암호화 기능  (0) 2010.07.02
오라클 pump 관련 자료  (0) 2010.06.30
오라클 기본 유저 정보  (0) 2010.06.30
반응형

Oradebug 사용법
- 적절한 권한을 가진 DB USER 로 sqlplus 로 접속
- 반드시 덤프할 오라클 프로세스를 지정한 후 사용

- SYNTAX : SQL>oradebug command <option>

일반 유저도 Try

SQL> show user
USER is "SCOTT"
SQL> oradebug setmypid
ORA-01031: insufficient privileges

 

SQL> conn / as sysdba
Connected.
SQL> show user
USER is "SYS"
SQL> oradebug setmypid
Statement processed.

==> 자신의 process ID 지정 해서 dump

 

일반 유저를 찾아서 지정 해보기

보통은[AIX 환경] ps aux | sort -k3 으로 cpu 과도 사용 Unix process ID 를 찾은 후

지정 해서 dump 를 떨군 후 분석을 하면 될듯

 

## Scott User 의 Process ID 찾기
SQL> select username, sid, serial#,PADDR from v$session where username ='SCOTT';

USERNAME                              SID    SERIAL# PADDR
------------------------------ ---------- ---------- --------
SCOTT                                  28         54 46CB5768

SQL> select * from v$process where addr = '46CB5768';

ADDR            PID SPID      USERNAME           SERIAL#
-------- ---------- --------- --------------- ----------
TERMINAL                       PROGRAM
------------------------------ ------------------------------------------------
TRACEID
--------------------------------------------------------------------------------
B LATCHWAI LATCHSPI
- -------- --------
46CB5768         29 283314    oracle                   2
pts/8                          oracle@seldw (TNS V1-V3)

 

## Unix 환경에서 파악

[CRAFT]seldw:/app/oracle/tg> ps -ef| grep 283314
  oracle 282448 290026   0 10:45:26  pts/7  0:00 grep 283314
  oracle 283314 284036   0 10:42:54      -  0:00 oracleCRAFT (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

 

SQL> oradebug unlimit
Statement processed.
==> Dump 화일 무제한으로 설정
SQL> oradebug setospid 283314
Oracle pid: 29, Unix process pid: 283314, image: oracle@seldw (TNS V1-V3)

==> Scott Process ID 를 지정 해서 dump
SQL> oradebug tracefile_name
Statement processed.
==> dump 화일명 체크

==> 나오지 않는다.

SQL> oradebug dump errorstack 3
Statement processed.
==> dump 화일에 실제 Write 되도록 command 를 날리기

SQL> oradebug tracefile_name
/app/oracle/admin/CRAFT/udump/ora_283314_craft.trc
==> 이제 화일명이 보임

 

# Event 로 Trace 걸기
SQL> oradebug setospid 283314
Oracle pid: 29, Unix process pid: 283314, image: oracle@seldw (TNS V1-V3)

# 10046 Event 에 대해서 Trace 생성도록 설정 하기
SQL> oradebug event 10046 trace name context forever, level 12
Statement processed.
SQL> oradebug event 10046 trace name context off
Statement processed.
SQL> oradebug tracefile_name
/app/oracle/admin/CRAFT/udump/ora_283314_craft.trc

 

CASE 1 : 특정 프로세스가 SPIN 또는 HANG
SQL> oradebug dump errorstack 3 .. 3분단위 3번수행
SQL> oradebug dump processstate 10 .. 비교1
SQL> oradebug event 942 errorstack 10 .. 비교2

 

CASE 1 은 특정 프로세스가 SPIN 또는 HANG 으로 보이는 경우입니다.
(1) Oradebug setospid 해당 프로세스를 덤프대상으로 지정하고
(2) Oradebug dump errorstack 3 으로 ERRORSTACK 을 2-3번 떠서
(3) CALL STACK 부분이 변하고 있는지 비교해봅니다.
변하고 있으면 SPIN 이고, 변하지 않고 있으면 HANG 이라고 결론 내릴 수 있습니다.
ERRORSTACK LEVEL 3 에 PROCESSSTATE DUMP 가 포함되므로
PROCESSSTATE DUMP 를 별도로 수행할 필요가 없습니다.
EVENT Command 에서 ERRORSTACK 를 설정할 때와 비교해보면, EVENT Command 는 해당 에러가 발생하는
시점에 에러스택이 생성되는 것이고, DUMP Command 는 Oradebug Command 를 수행하자마자 에러스택이
생성됩니다.

 

CASE 2 : 데이터베이스 SPIN 또는 HANG
SQL> oradebug dump systemstate 10 .. 3분간격 3번수행
= alter session set events 'immediate trace name SYSTEMSTATE level 10';


케이스 두번째, 드디어 SYSTEMSTATE DUMP 입니다.
이 Command 는 아마도 oradebug 에서 가장 많이 사용되는 명령어로
alter session set events 'immediate trace name SYSTEMSTATE level 10'; 과 같습니다.
보시다시피 Oradebug Command 가 훨씬 간단하고 Rule 만 알면 외울 필요도 없습니다.
인스턴스 HANG 시 3분 간격으로 3번을 수행한 결과가 있어야 Slow Performance 인지,

진짜 HANG 이였는지 판단할 수 있습니다.


SQL> oradebug dump systemstate 10
ORA-00074: no process has been specified
SQL> alter session set events 'immediate trace name systemstate level 10';

Session altered.

 

CASE 3 : 프로세스 메모리가 비정상 증가하는 경우
SQL> oradebug dump heapdump 5 .. PGA+UGA


CASE 4 : SGA 부족으로 ORA-4031 가 발생하는 경우
SQL> oradebug dump heapdump 2 .. SGA
event="4031 trace name HEAPDUMP level 2" in initSID.ora

 

CASE 6 : 리커버리시 데이터파일 상태 불일치 에러시
SQL> oradebug dump controlf 10
SQL> oradebug dump file_hdrs 10
==>테스트시  임의의 프로세스 지정을 해야 trace 화일이 생성 된다.

SQL> oradebug dump controlf 10
ORA-00074: no process has been specified
SQL> oradebug setospid 283314
Oracle pid: 29, Unix process pid: 283314, image: oracle@seldw (TNS V1-V3)
SQL> oradebug dump controlf 10
Statement processed.
SQL> oradebug tracefile_name
/app/oracle/admin/CRAFT/udump/ora_283314_craft.trc
SQL> oradebug dump file_hdrs 10
Statement processed.
SQL> exit

 

SQL> oradebug hanganalyze 3
Hang Analysis in /app/oracle/admin/CRAFT/udump/ora_89222_craft.trc
프로세스 또는 인스턴스 HANG 진단 및 분석시 유용
HANGANALYZE [level]
1-2 Only HANGANALYZE output, no process dump
3 Level 2 + HANG 으로 추정되는 프로세스 덤프
4 Level 3 + WAIT CHAIN 의 BLOCKER 프로세스
5 Level 4 + WAIT CHAIN 의 모든 프로세스
10 모든 프로세스 덤프

SQL> oradebug hanganalyze 3 .. 권장레벨, 또는 1
Hang Analysis in /home/ora920/ora920_1190.trc
HANGANALYZE TRACEFILE SECTIONS 설명
 CYCLES : Deadlock 관계 세션들의 CHAIN
 BLOCKER OF MANY SESSIONS : 10개 이상의 세션을 blocking 하는 BLOCKER 제시
 OPEN CHAINS : 1개 이상의 타 세션들을 blocking 하는 세션이 포함된 WAIT CHAIN
 OTHER CHAINS : OPEN CHAIN 의 세션들과 간접적으로 관련있는 프로세스 리스트

EXTRA INFORMATION : 덤프 레벨에 따른 프로세스 Errorstack 등의 추가 정보
STATE OF NODES : 모든 세션들 DEPENDENCY GRAPH
  IN_HANG - HANG
  IGN - IGNORE
  LEAF - A waiting leaf node
  LEAF_NW - A running leaf node
  NLEAF - STUCK
세션 STATE 설명입니다.
IN_HANG : 심각한 상태로, 이 상태의 세션은 DEADLOCK 가능성이 있습니다 .
IGN and IGN_DMP : IDLE 상태이므로 무시하셔도 됩니다.
LEAF and LEAF_NW : 이 상태로 Wait Chain 의 가장 앞에 있으면,

                             바로 이 세션이 Blocker 세션입니다.
NLEAF : STUCK 세션으로, 다른 세션이 리소스를 잡고 안 놓아 주는 상태

           로 Performance 이슈일가능성이 높습니다.
 
DB HANG 이것만은 알아두세요!!!
데이터베이스 HANG : DB 연결될 때
SQL> oradebug setmypid

자신의 Process ID 지정 아마도, trace file 생성을 위해서 임의로 지정하는 듯
SQL> oradebug unlimit

Trace file 무한으로 설정
SQL> oradebug hanganalyze 1 

빨리 Blocker 찾으세요

Trace 화일을 통해서 문제의 Process ID 를 서치

심도 있게 더 깊이 분석시 아마도 setospid를 통해서 Blocker ID 를 찾은수

다시 trace 를 시도 하면 될듯
SQL> oradebug dump systemstate 10 ..

다른세션에서 3분3번

 

데이터베이스 HANG : DB 연결안 될 때
$ dbx .a PID $ORACLE_HOME/bin/oracle .. Oracle PID
dbx) call ksudss(10) or print ksudss(10)
dbx) detach



RAC에서 다른 Instance와의 연관된 내용까지 분석하려면 다음과 같은 명령문을 사용해야 한다.

SQL> oradebug setinst all
SQL> oradebug --g def hanganalyze 1

 

SQL> oradebug hanganalyze <level> -- 예: oradebug hanganalyze 3
Level에 따른 출력 내용은 다음과 같다.

    * 10 - Dump all processes (IGN state)
    * 5 - Level 4 + Dump all processes involved in wait chains (NLEAF state)
    * 4 - Level 3 + Dump leaf nodes (blockers) in wait chains (LEAF,LEAF_NW,IGN_DMP state)
    * 3 - Level 2 + Dump only processes thought to be in a hang (IN_HANG state)
    * 1-2 - Only HANGANALYZE output, no process dump at all


[출처] Oradebug Command|작성자 타락천사

반응형
반응형
 
AWK와 SED는 비슷한 또래의 사촌이다. 유닉스 초창기에 개발됐고 훌륭한 기능을 제공하므로 1979년 이후 다양한 유닉스 변종들과 유닉스-like 운영체제에 꼭 포함돼 많은 사랑을 받아왔다. 둘이 맡은 역할은 텍스트 프로세싱이다. 유닉스 프로그램들은 데이터를 일반 텍스트 파일로 저장하는 경우가 많기 때문에 유닉스 환경에서 AWK와 SED를 활용함으로써 처리할 수 있는 작업은 종류를 셀 수 없을 것이다. 게다가 파이프라인이 가능하므로 표준 출력을 AWK와 SED의 표준 입력으로 받아 처리 할 수 있으므로 텍스트가 들어가는 모든 작업에 사용될 수 있다해도 과언은 아니다. 이 둘은 헤아릴 수 없이 많이 카피돼 지난 한 세대 동안 메인프레임이나 대형 서버에서 프로세스로서 숨쉬어왔다. 하지만 80년대 중반에 더 강력한 기능을 제공하는 펄이 등장했고 그후로 AWK와 SED의 인기는 점점 사그라들었다. 게다가 AWK와 SED의 스크립트를 작성하기도 해석하기도 어렵기 때문에 조금이라도 복잡한 스크립트를 프로그래밍할 필요가 생기면 펄이나 파이썬을 추천하는 추세다. 

그러나 더 강력한 기능과 더 나은 개발 용이성을 제공하는 언어의 등장에도 불구하고 AWK와 SED는
30년 넘게 살아남았다. 대체 그 이유가 뭘까? 유닉스 초창기에 대한 향수 때문에 올드 프로그래머들이 사용하는 걸까? 아니면 복잡한 프로그래밍을 즐기는 소수 마니아들이 끈질기게 그 둘을 놓지 않기 때문일까? 아마 직접 써보면 알게 될 것이다.


이 문서의 목적
AWK와 SED에 처음 발을 들여놓는 사람들을 위한 가이드라인이다. AWK나 SED의 모든 기능을 다루지는 않았고, 문서 곳곳에서 '그밖의 내용은 맨페이지를 참고하라'는 식의 말이 나온다. AWK와 SED에 필수적인 내용을 조감하기 위함이다.

현재 문서 버전

2009년 11월 24일 버전 <- 현재
2009년 11월 21일 버전

AWK와 SED는 사용하기 어렵다?
많은 이들이 AWK와 SED로 작성된 스크립트를 보고 해석하기 난해해 하는 이유는 많은 사용자들이 AWK와 SED가 프로그래밍 언어인지 모르기 때문이라 생각한다. 사용방법이 비교적 간단해서 금방 배울 수 있는 유틸리티와 혼동하여 "AWK나 SED도 유틸리티인데 이걸 공부할 필요까진 없다" 라고 착각하기 때문에, 유틸리티 치고는 AWK와 SED 는 어렵다고 손사래 치는 것이다. 그러나 AWK나 SED도 엄연히 프로그래밍 언어고 어느 정도의 지식이 있어야 사용할 수 있다. 하지만 언어치고는 습득에 걸리는 시간이 길지 않고, 이 짧은 문서에 많은 내용을 담을 수 있을만큼 알아야할 것이 많지 않기 때문에 어려울 거란 염려는 넣어두시라. ;)

작성자
정준영; 이 문서는 2009년 11월, 한주마다 열리는 HLUG 내부 세미나를 위한 발표자료를 토대로 작성하였다.

목차
I. AWK & SED 역사적 배경 (이 포스트에서 설명)
II. 정규표현식 소개 (이 포스트에서 설명)
III. AWK (이 포스트에서 설명)
IV. AWK Examples(이 포스트에서 설명)
V. SED (다음 포스트에서 설명)
VI. SED Examples(다음 포스트에서 설명)


I. AWK와 SED 배경

AWK 역사적 배경

1977년 Bell Laboratories의 Alfred Aho, Peter Weinberger 그리고 Brian Kernighan이 처음 개발했다. 이 셋의 이름을 따 AWK라 부르고 auk[ɔ́ːk]로 발음한다. 옆에 있는 사진은 바다쇠오리라는 새인데 영어로 auk라 부른다. AWK와 발음이 같기 때문에 AWK 책에 표지모델로 쓰기이기도 했다.
1979년 Version 7 Unix에 처음 배포되었다. V7 Unix는 역사적으로 의미가 있는 유닉스다. 유닉스는 벨연구소에서 PDP-7에 MULTICS를 이식하면서 개발이 시작됐고 1970년 PDP-11에 포팅되면서 UNIX의 첫번째 판이 나왔다. 1973년 Versioin 4 Unix는 C언어로 재작성됐고 1974년 대학에 널리 알려지게 되면서 대학과 벨연구소가 함께 개발하기 시작했다. 그리고 1979년에 V7이 나왔고 여기에 최초로 C 컴파일러와 본셸이 들어갔다. 물론 AWK와 SED도 이 버전에 최초로 포함됐고 make도 이때 포함됐다. 역사적으로 의미가 있다는 이유는, V7이 research unix로서 널리 알려진 유닉스 중 마지막 버전이기 때문이다. 즉, 1980년대  들어서 유닉스가 상업적으로 사용되기 시작했는데, 그 전에 나온 마지막 유산이라는 뜻이다. 물론 V8, V9, V10까지 나오긴 했었지만 V7만큼 알려지진 않았다. 게다가 많은 유닉스 변종들은 V7을 기반으로 했고 그 중 BSD와 SystemV는 또 그 후에 모든 상업적 유닉스의 기반이 됐기 때문에 역사적으로 V7이 중요한 의미를 가진다고 말할 수 있다.


SED 역사적 배경

SED는 Stream EDitor에서 따온 이름이다. 읽을 때는 세드라고 발음한다.  1973년 벨연구소의 Lee E. McMahon이 개발했다. 추측컨대 그 당시의 벨연구소는 지금의 구글보다 더 높은 위상을 가졌을 것 같다. 벨연구소는 전화장비, 물리분야, 네트워크, 소프트웨어 등 첨단 기술의 리더 역할을 했다. 그 연구소에서 완료한 연구 업적으로 7번의 노벨상이 수여됐다고 한다. 하지만 1996년 벨연구소의 전화장비와 물리연구분야가 Lucent Technologies로 독립했고 소수만 남아서 AT&T Bell Laboratories를 이어갔다. 그후 AT&T Laboratories로 존재하다가 2005년에 AT&T Corp.가 통째로 SBC Communications에 인수됐고 SBC Communications는 자신의 이름을 AT&T Inc.로 바꿨다. 그리고 AT&T Corp.의 일부였던 AT&T Laboratories는 SBC Communications의 R&D  부서에 흡수됐고 그 부서 역시 AT&T Labs. Inc 로 자신의 이름을 바꿨다. 예전에 정점을 달리던 AT&T는 사실상 SBC Communications에 흡수되어 사라졌다. 단지 AT&T 이름이 상징적이기 때문에 SBC Communications가 그 이름을 계속 사용하는 것이다.
SED는 AWK와 마찬가지로 1979년 Version 7 Unix에 처음 배포됐다. 그러나 80년대 중반에 perl 등장했고 널리 알려지기 시작하면서 AWK와 SED의 사용 빈도는 급격히 줄었다. 왜냐하면 조금만 길어져도 스크립트가 너무 복잡해지기 때문이다. 그렇기 때문에 복잡한 프로그래밍으로는 거의 사용되지 않고 관용적인 one-liner로써 명맥을 이어가고 있는 실정이다. sed는 ed로 부터 비롯됐고 perl에 영향을 주었다.
*one-liner 라는 단어는 명령행에 한줄로 쓰여져 동작하는 프로그램을 뜻한다.



II. 정규표현식

AWK와 SED는 정규표현식이 적용되지 않아도 작동하지만, 정규표현식을 사용하면 AWK와 SED로 할 수 있는 일이 훨씬 많아진다.

정규표현식이란 텍스트 안에 있는 복잡한 패턴을 표현하는 방법이다. 정규표현식은 정규식으로 줄여서 쓸 수 있고 regular expression은 regex 또는 regexp로 줄여서 쓸 수 있다. 발음하기는 regex가 편하고 레긱스 내지는 레직스라고 읽을 수 있다. 대체 regexp는 어떻게 발음하는지 모르겠다. 아시는 분은 제보 부탁드린다 ;^)

정규표현식은 automata theory와 formal language theory 연구에서 시작됐다. 그리고 최초로 정규표현식을 적용시킨 유틸리티는 Ken Thompson의 QED이다. 또한 나중에 Ken Thompson은 ed에도 정규표현식 기능을 넣었고 이로 인해 정규표현식이 널리 알려지게 됐다. 현재 정규식을 지원하는 유틸리티 중에 가장 유명한 것은 grep일 것이다. grep은 ed에 직접적으로 영향을 받았다. ed 명령어 g/re/p에서 그 이름을 따올 정도였으니까 말이다. 현재 다양한 에디터, 프로그래밍 언어 (특히 스크립팅 언어) 그리고 많은 텍스트 프로세싱 유틸리티들에서 정규표현식이 지원된다.

이 문서에서는 널리 쓰이는 AWK와 SED의 관용구들을 이해할만한 선에서 정규표현식의 일부를 소개한다. 그 선이라는 것은 내 경험을 바탕으로 정한 것이므로 절대 '정규표현식은 이게 전부다'라고 믿지는 말라 :P

누구나 워드 프로세서의 '찾기' 기능을 써본 적 있을 것이다. 정규표현식이 없는 '찾기'는 사용자가 입력한 스트링에 문자 그대로 정확히 매칭되는 단어 또는 문장만 찾을 수 있다. 그런데 정규표현식을 사용하면 '찾기' 기능에 "전체 텍스트 중에서 이러저렇게 생긴 부분을 찾아줘"라고 말할 수 있다. 다시 말하자면, "이 패턴을 가진 부분을 찾아라"라고 명령할 수 있다는 얘기다.

Characters and Character class

abc : abc 캐릭터 그대로
\t   : tab 캐릭터
\n  : newline 캐릭터
[abc] : a or b or c 대괄호는 정규식에서 특수한 의미를 가진다. 대괄호는 캐릭터 클래스를 형성한다. 문자 그대로의 대괄호를 매칭시키고 싶으면 백슬래시를 앞에 두어야 한다. \[ \]
[a-z] : 소문자 a~z 캐릭터 클래스는 범위로 지정할 수도 있다.
[A-Z] : 대문자 A~Z
[0-9] :  숫자 0~9
[a-zA-Z0-9] 다중 범위를 지정할 수도 있다.
[^abc] : abc 제외(반드시 ^이 맨 처음에 나와야함) 캐릭터 클래스에 맨 첫 글자가 ^면 ^이 특별한 의미를 가진다. 캐릭터클래스 안에 있는 캐릭터를 제외한 아무 캐릭터를 뜻한다. 만약 캐릭터 클래스의 맨처음이 아니라 중간에 ^이 들어가면 문자그대로의 ^을 뜻한다.
 .      : 아무 character. 점하나가 아무 캐릭터 하나를 뜻한다. 빈칸도 되고 알파벳, 숫자, 특수기호 등도 가리킨다.


경계(boundary)


^  : 행의 맨 처음
$  : 행의 맨 끝, 그렇기 때문에 ^$은 아무캐릭터가 없는 행 즉, 빈행을 의미한다
\w : 단어. 영숫자를 의미함.
\W:  단어가 아닌 캐릭터. 즉, ~`!@#$%^&*()-+=|\{}[];':"?/<>,. 그리고 공백문자를 뜻한다.
\b: 단어 경계(이질성)
\B: 비 단어 경계(동질성)


이해를 돕기 위해 \b, \B, \w, \W의 예를 들어보겠다.
abcdef:!~ghi-jkl에 대해
 패턴 매칭
(\B\w)* abcdef:!~ghi-jkl
 (\b\w)* abcdef:!~ghi-jkl
 (\b\W)* abcdef:!~ghi-jkl
 (\B.\B)* abcdef:!~ghi-jkl
 (\b.\b)* abcdef:!~ghi-jkl

즉 \B는 자기와 같은 그룹(단어냐 비단어냐)에 속한 녀석에 둘러쳐졌는지 보는 것이고 \b는 자기와 다른 그룹에 속한 녀석에 둘러쳐졌는지 본다.


횟수(quantities)


* : 0번 이상 나옴, 예) a*b  : bbb 매칭
+ : 1번 이상 나옴, 예) a+b  : bbb 매칭 안됨
?  : 0,1번
{n,m} n~m번
{,m} ~m번
{n,} n번이상
{x} x번


캡처링 그룹과 백레퍼런스(capturing groups and back references)

()  패턴을 그룹으로 묶음, 그룹화의 가장 큰 목적은 나중에 특정 그룹을 가리키기 위해서이다.
\n n번째 그룹 가리키는 백레퍼런스
백레퍼런스 지정 순서: 왼쪽 괄호가 등장한 순서대로 해석한다.
((A)(B(C)))  
               \1 : ((A)(B(C)))
   \2: (A) 
   \3: (B(C))
               \4: (C)


백레퍼런스의 키포인트: 백레퍼런스로 가리키는 것은 매칭된 결과 값임을 주의! 패턴을 가리키는 것이 아님!

여기저기서 갖고 온 것들 :P

\  : 인용부호; 특수 캐릭터의 해석을 막음
       예) \^ 행의 처음이라는 의미 상실 
            \\ 알파벳에 특수한 의미를 부여하는 기능(이스케이프 시퀀스) 상실
            \. 아무 캐릭터나 가리킬 수 있는 기능 상실
X|Y : X or Y
\s : 공백문자
\S : 공백문자를 제외한 캐릭터
[\]: \\ 한 것과 의미 동일
[.^]: \. 과 \^ 한 것과 의미 동일



III. AWK

syntax

1. pattern{ action statements }
2. function name(parm list) { statements }

2번은 함수를 정의하는 문법이다. C와는 조금 다른 점은 parm list에 매개변수 뿐만아니라 로컬변수도 써줘야 하는 점이다. 그 점 외에는 특별한 것이 없다.

awk의 프로세싱은 입력 스트림 => awk processing => 출력 스트림이다. 입력 스트림은 파일 또는 표준 입력을 지정할 수 있다. 출력 스트림 역시 파일 또는 표준출력임은 두말하면 잔소리다. 그중 awk processing 부분이 우리가 주목해야할 부분인데 1번에 나온 문법대로 프로그래밍을 해야 한다.
즉 입력스트림을 받아서 pattern에 적용해 보고 패턴에 일치하면 action statements 를 실행하는 것이다. 또한 다수의 pattern{ action }을 체인으로 사용할 수 있다. 1번을 조금 더 C와 비슷한 모양으로 고치면 이렇게 쓸 수도 있다. pattern{ action } 에서 pattern 부분을 생략하고 action의 if 문 안에 패턴을 검사하는 statement를 넣었다.
{
   if (pattern) {
         action statements
   }
}


보다시피 pattern{ action }의 pattern 은 생략가능 하다. 이 경우 모든 입력스트림에 대해 {action}을 수행하게 된다.

그리고 pattern{ action } 에서 { action }도 역시 생략 가능하다! 이 경우 pattern과 일치하는 입력 스트림 부분을 print하는 action이 자동으로 실행한다.


AWK를 배우는데 문법 구조 외에 알아야 할 게 또 있다. 바로 미리 정의된 변수들(pre-defined variables)이다. 이 변수들은 각각 특별한 값을 가지게 되는데 상황에 따라 매번 변하는 변수도 있고 사용자가 변경하지 않는한 계속 그대로인 변수도 있다.

또한 AWK는 일반변수와 배열도 지원한다.

그리고 다양한 표준 함수들도 가지고 있다.

이제 어째서 AWK를 프로그래밍 언어라고 하는지 감이 오지 않는가? 이제 위에 나열한 AWK의 기능들을 설명하겠다. 이 문서는 레퍼런스라기보다는 초보자용 가이드라인이므로 awk의 모든 기능을 설명하는 대신 자주 사용되는 기능들만 설명한다.


pre-defined variables

미리 정의된 변수들이 있다. built-in variables 라고 부르기도 한다. 이 변수들을 이해하기 위한 몇가지 개념을 먼저 소개하겠다. record나 field는 awk의 입력으로 들어온 전체 텍스트 중 일부다. 전체 텍스트가 awk를 거치는 모습은 간단히 이렇게 그릴 수 있을 것이다.
Input ==> awk processing ==> output
input 은 표준입력이 될 수도 있고 평범한 파일일 수도 있는데 awk는 작업을 처리하기 위해서 input을 통째로 작업대 위에 올려놓지 않고 부분부분 잘라서 올려놓는데 이 때 작업대 위로 올려놓은 게 레코드다. 그리고 그 레코드는 또 필드로 이루어져 있다.


이제 '변수이름: 의미' 형식으로 미리정의된 변수들의 의미를 중요한 것만 알아보겠다.

RS: record separator (디폴트는 개행문자)
FS: field separator (디폴트는 공백문자)
NF: the number of fields (FS로 나뉜 한 레코드 안의 필드 개수)
ORS: output record separator(디폴트는 개행문자)
NR: total number of record so far(현재 라인 번호)
ARGC, ARGV: 매개변수의 개수와 매개변수를 가리키는 변수
FNR: number of record in the current input file
OFS: ouput field separator(디폴트는 공백문자)
FILENAME: name of input file
SUBSEP: separate multiple subscripts in array elements(,; \034; \0x1C)
IGNORECASE: 값이 0이 아니면 패턴 매칭에 대소문자 구별 안 함


RS는 awk가 전체 텍스트 중 작업대 위로 레코드를 올릴 때 어떤 단위로 올릴지 정하는 변수라 할 수 있겠다. 디폴트 값은 newline 캐릭터이므로 이 때 awk는 grep이나 sed처럼 한 줄 씩 끊어서 작업한다고 말할 수 있다.
FS는 레코드 내의 필드들의 구분자이다. 기본 값은 공백이므로 어떤 레코드의 내용이 abc def ghi jkl 이면 1번 필드($1)는 abc,2번($2)은 def 이런 식이다. 그리고 $0은 abc def ghi jkl 이다. 즉 현재 레코드의 전체 부분을 가리킨다.
awk의 매개변수에 파일을 여러개 지정했다면 FNR과 NR의 차이점도 알아야 한다. FNR은 지금 awk가 작업하고 있는 파일 내에서 몇번째 레코드인지 가리키고 NR은 파일 구분 없이 맨처음부터 지금까지 총 몇번째 레코드인지 가리킨다.
SUBSEP은 배열 사용시 필요한 내용인데, 배열을 설명할 때 부가 설명드리겠다.

시험삼아 위에 설명한 내장 변수들을 사용한 몇가지 간단한 관용구처럼 사용되는 one liner들을 따져보자.

1. awk 'NR%2==0{ print $0 }'
2. awk 'NR%2'
3. awk '0'
4. awk '”0”'
5. awk 'NR>5&&NR<10'
6. awk '$0 = NR" "$0'

1번은 짝수 줄NR%2==0이면 출력하라{ print $0 }는 뜻이다. 2번은 홀수 줄이면 출력하라는 뜻이다. 왜냐하면 NR이 홀수 줄이면 NR%2 가 0이 아니므로 디폴트 액션인 { print $0 }이 출력되기 때문이다. 여기서 NR%2의 값은 0또는 1인데 0은 false를 뜻하고 0이 아닌 숫자는 true를 뜻한다. 3번은 아무 줄도 출력하지 않는다. 왜냐하면 항상 0, false이기 때문이다. 4번은 항상 출력한다. "0"은 문자열이기 때문에 항상 참이다. 5번은 6,7,8,9 줄을 출력한다. 6번은 줄앞에 줄번호를 붙인다. $0은 현재 레코드인데 $0 = NR" "$0 은 $0에 NR" "$0을 대입하라는 의미이다. 중간에 " " 은 단지 줄번호(NR)과 레코드($0) 사이에 공간을 두기 위해 붙인 문자열에 지나지 않는다.

변수와 배열

변수는 숫자거나 스트링일 수 있다. awk의 변수와 배열은 따로 초기화하거나 타입을 지정할 필요가 없으며 필요시 자동으로 형변환이 된다. 즉 사칙연산이 필요할 때는 숫자였다가 문자열 이어붙이기를 할 때는 스트링이 되기도 한다.

초기화가 필요 없으므로 곧바로 a++; 이렇게 쓸 수도 있다. 이때 a의 값은 1이 된다. 왜냐하면 초기화하지 않은 변수의 값은 숫자의 경우 0이기 때문이다. 그리고 변수에 octal 과 hexadecimal 값을 넣을 수 있다.  a=0nn;, b=0xnn; 이렇게 사용하면 된다.

변수에 스트링을 대입하는 방법은 a="string" 이런 식이다. 또한 스트링 안에 이스케이프 시퀀스도 사용할 수 있다. 몇가지 이스케이프 시퀀스의 예는 다음과 같다.
\\: 백슬래시 캐릭터 그대로. 백슬래시는 이스케이프 시퀀스를 만들 때 사용되므로 문자 그대로의 백슬래시를 써야할 때는 백슬래시를 두개붙여쓴다.
\a: ASCII의 BEL 캐릭터
\b: 백스페이스 캐릭터
\n: 개행문자
\r: 캐리지 리턴
\t: 수평 탭
\v: 수직 탭
\ddd: octal value로 표현되는 캐릭터. 0-7까지의 숫자만 이용해서 캐릭터를 표현하며 범위 밖의 숫자 또는 문자는 이스케이프 시퀀스에 해당하지 않는다. 즉 그 앞 부분까지만 octal value로 표현되는 이스케이프 시퀀스다. 예를들어 "\438"은 #8이다.
\xnnn: hexadecimal value로 표현되는 캐릭터. 역시 \x 뒤를 따르는 모든 16진수 숫자들을 이스케이프시퀀스로 받아들이고 범위를 벗어나면 그냥 문자그대로로 인식한다. 예를들어 "\x23G"는 #G이다.


배열도 변수와 마찬가지로 초기화가 필요하지 않다. 다짜고짜 a[0]++; 이런 식으로 쓸 수 있다. 그리고 특이하면서 유용하게 사용되는 특징은 배열의 인덱스에 스트링을 넣을 수 있다는 점이다. 그리고 숫자로는 음수나 소수를 넣을 수 있다. 예를 들어
a["Foundations of AWK"]=1; 이렇게 쓰거나 a[-12.07]++; 이렇게 쓸 수도 있다. 또한 awk의 배열은 다차원 배열을 흉내낼 수 있는데 다음과 같이 쓸 수 있다. 
a["Foundations of AWK","Junyeong"]="Jeong";
a["Foundations of AWK","Alfred"]="Aho";
a[0,1,0]="Kernighan";
i=0; j=1; k=1;
a[i,j,k]="Weinberger";

즉 배열의 섭스크립트를 여러 문자열이나 숫자의 조합 또는 변수의 조합으로 사용할 수 있으며 조합시에 , 를 사용하는데 이것은 아까 pre-defined 변수에서 SUBSEP 변수의 값인 캐릭터이다. 이 캐릭터가 눈에 잘 띄지 않는다면 SUBSEP변수를 바꿔서 다른 캐릭터로 변경해도 되고 캐릭터를 octal 이나 hexadecimal 값으로 기입해도 상관없다. 즉 위의 예를
a["Foundations of AWK\034Junyeong"]="Jeong";
a["Foundations of AWK\034Alfred"]="Aho";
이렇게 쓸 수 있다는 말이다. 물론 a["Foundations of AWK","Junyeong"]="Jeong"; 으로 값을 할당하고 a["Foundations of AWK\034Junyeong"] 으로 값을 가져오는 것도 당연 가능하다. 단지 "," 캐릭터를 스트링의 이스케이프 시퀀스로 표현했을 뿐이기 때문이다.

그리고 배열의 특정 섭스크립트를 검색하는 연산자로서 in 이 있다. 사용법은 subscript in array이다. 만약 위의 예를 적용하면
if ("Foundations of AWK\034Junyeong" in a) print a["Foundations of AWK\034Junyeong");
이다. 혹은 if (("Foundations of AWK","Junyeong") in a) print a["Foundations of AWK","Junyeong"]; 도 똑같다.



패턴

AWK의 syntax, awk 'pattern{ action statements }' 중에서 pattern 부분을 작성하는 방법은 다음과 같다.

BEGIN{ }: 모든 인풋보다 먼저 실행되는 statements를 지정, 즉 awk의 작업대에 첫 레코드가 올라가기 전에 실행되는 statement들의 블록을 지정하는 셈이다. 초기화 작업을 하는 곳이라고 생각하면 된다. BEGIN 패턴은 한 awk 명령에 여러번 나올 수 있는데 모든 BEGIN블록은 한데 모아진다.
END{}: 더 이상 인풋이 없을 때 실행되는 statements지정. 역시 END블록은 여러번 나올 수 있고 하나의 END블록으로 모아진다.
/정규식/: / / 로 묶어서 정규식을 사용할 수 있다.
패턴1 && 패턴2: AND 논리 연산, 물론 패턴이라는 말은 /정규식/도 내포한다.
패턴1 || 패턴2: OR 논리 연산
!패턴: NOT 논리 연산,
패턴1, 패턴2: range pattern인데 패턴1인 레코드로부터 패턴2인 레코드까지인 범위를 지정한다.



연산자들

기본적으로 C에서 사용할 수 있는 연산자들(포인터나 구조체 관련한 연산자 제외)을 사용가능하다. 거기에 덧붙여 AWK에서 사용되는 특별한 연산자들이 있으니 그것만 여기 소개하겠다.
$: field reference, 레코드에서 FS로 구분되는 필드를 가리킨다. 특별히 $0은 모든 필드들을 뜻한다.
space: 공백 연산자는 스트링과 스트링을 붙이는데 사용한다.
|, |&: getline, print, printf에 사용되는 piped I/O
~, !~: 정규표현식 매치, 비매치. 정규식을 연산자의 오른쪽에 써야만 한다.
in: 배열에서 특정 섭스크립트 검색

제어문

C에서 사용하는 제어문과 비슷하다. AWK는 C를 많이 따랐기 때문에 비슷한 것은 당연하다. 다만 배열에 관련해서 delete문이 있고 switch문은 없는데, switch 문은 awk의 옵션으로 --enable-switch로써 사용가능하다.
if (condition) statement [ else statement ]
while (condition) statement
do statement while (condition)
for (expr1; expr2; expr3) statement
for (var in array) statement
break
continue
delete array[index]
delete array
exit [ expression ]
{statements }


I/O 문

I/O statements는 여러 종류가 있지만 그중 자주 사용되는 getline과 print, printf만 알아보겠다. 다른 종류(close, system, fflush, next, nextfile) 대해서는 맨페이지를 참고하시라 ;^)

getline: 다음 레코드를 $0로 설정함
getline < "file": 다음 레코드를 "파일"에서 가져온다
getline var: 다음 레코드를 변수 var에 넣는다
getline var < "file": 다음 레코드를 "파일"에서 가져와서 변수 var에 넣음
"command" | getline [var]: "command"를 실행하여 표준출력을 파이프로 넘기고 넘어온 입력을 getline이 $0 [또는 변수var]으로 설정한다
"command" |& getline [var]: "command"를 co-process로 실행시켜 표준출력을 파이프로 넘이고 getline은 넘어온 입력을 $0 [또는 변수var]로 설정한다
print: 현재 레코드를 출력한다. 출력된 레코드는 ORS가 맨 끝에 붙음
print expr-list: 표현식을 출력한다. 각 표현식은 OFS로 구분되어 출력된다. 예를 들어 print $1, $2;
print expr-list > "file": 표현식을 "file"로 출력한다
print expr-list >> "file": 표현식을 "file" 끝에 덧붙인다
print expr-list | "command": 표준출력을 파이프에 쓰고 "command"에서 그 파이프를 표준입력으로 받는다
print expr-list |& "command": print 표준출력을 파이프에 쓰고 "command"는 co-process로 실행돼 파이프에서 표준입력을 읽는다
printf format, expr-list: C의 printf처럼 포맷을 지정해서 표현식을 출력한다(포맷은 C와 유사하며 자세한 내용은 awk맨페이지를 참고하시라)
printf format, expr-list > "file": 포맷을 지정해서 표현식을 파일로 출력한다.

위의 설명들은 쭉 읽어보면 아마 하나 빼고 바로바로 이해가 될 내용일 것이다. 그 하나는 바로 co-process 를 실행시킨다는 |& 연산자를 사용한 부분일 것이다.
"command" | getline 이나 print | "command" 중 전자는 각각 "command"의 표준출력을 getline의 표준입력으로 보낸 것이고, 후자는 print의 표준출력을 "command"의 표준입력으로 보낸 것이다. 둘 다 일방통행이라는 공통점이 있다. 그런데 |& 연산자를 사용할 시에는 "command"를 co-process(awk와 어깨를 나란히 하고 같이 뛰는 프로세스)로 실행시키게 된다. 그러므로 양방향 통신이 가능한데, 무슨 뜻이냐하면 print |& "command1"; "command1" |& getline 처럼 사용해서 print로써 명령으로 입력을 보내고 getline으로 결과를 받아본다는 뜻이다. 당연히 양쪽에 기입된 "command1"은 서로 같아야 출력을 올바로 볼 수 있다. 실제 예를 보면 확실히 이해가 될 것이다.
to_upper 배시 셸 스크립트
#!/bin/bash
#set -x
while read arg
do
    echo "$arg" | tr '[a-z]' '[A-Z]'
done

g6라는 awk 스크립트
{
  print $0 |& "./to_upper"
  "./to_upper" |& getline hold
  print hold
}

이제 이 awk 스크립트를 명령행에서 이렇게 실행시킨다
$ awk -f g6 < SOMEFILE

결과는 SOMEFILE 안에 있는 모든 영소문자들이 영대문자로 치환되어 출력된다. 만약 g6의 |&대신 |을 사용한다면 의도한대로 실행되지 않을 것이다. 비록 첫번째 statement는 ./to_upper로 print의 출력을 입력시킬 순 있지만 두번째 statement의 ./to_upper 프로세스는 첫번째 statement에서 돌아간 ./to_upper의 프로세스랑 다른 것이므로 원하는 결과는 얻을 수 없다!

I/O문에서 사용하는 특별한 파일들

리다이렉션을 이용해 파일로 print, printf 의 결과를 출력하거나 getline으로 파일에서 입력을 받을 수 있는데, 몇몇 파일이름들은 이미 awk가 특별한 의미를 부여해 놓았으므로 파일시스템 상의 파일을 의미하진 않는다.

/dev/stdin: 표준입력
/dev/stdout: 표준출력
/dev/stderr: 표준에러
/dev/fd/n: n번 파일디스크립터
/inet/tcp/lport/rhost/rport: TCP/IP 커넥션. 로컬의 포트는 lport, 원격호스트는 rhost, 원격포트는 rport. lport를 0으로 지정하면 운영체제가 알아서 선택한다.
/inet/udp/lport/rhost/rport: UDP/IP 커넥션. TCP/IP 와 사용법 같다.

그리고 현재 실행 중인 awk 프로세스에 대한 정보를 얻기위해
/dev/pid, /dev/ppid, /dev/pgrid, /dev/user 를 사용할 수 있다. gawk에서는 이 파일들 대신 미리정의된 변수인 PROCINFO 배열을 사용한다. PROCINFO에서 사용되는 섭스크립트는 다음과 같다. "FS", "egid", "euid", "gid", "group1", "group2", "pgrpid", "pid", "ppid", "uid", "version"


AWK가 제공하는 표준 함수들

표준함수에 대한 내용은 이문서에 설명하지 않겠다. 함수에 대한 설명이 맨페이지에 일목요연하게 나와있기 때문이다. 다만, 표준함수들에 대한 분류만 보기 좋게 써보겠다.
Numeric functions
String functions
Time functions
Bit Manipulation functions
Internationalization functions(since gawk 3.1)

뭐니뭐니해도 스트링 함수들이 가장 자주 사용되므로 거기에 있는 유용한 함수들은 잘 알아두는 게 좋다.


사용자 정의 함수

맨처음 syntax 섹션에서 function name(parm list) { statements }라고 적어놓은 것을 기억할 것이다. 이게 함수를 정의하는 방식이다. 특이한 점은 parm list 에 로컬 변수도 적어줘야 하는 점이다. 그리고 함수이름 name과 왼쪽 괄호 ( 는 떨어져서 안 된다. 예를 들어
function test(p, q,          i, j) {
      statements
}
p,q 는 함수를 호출 시 넘겨야하는 파라미터고 i,j 는 statements에서 사용되는 로컬 변수이다. 관습적으로 파라미터와 로컬변수 사이는 널찍하게 스페이스를 둔다.


awk 옵션들

커맨드라인에서 awk를 실행시킬 때 유용하게 쓸 수 있는 옵션 몇가지를 추려보았다.
-F fs: FS의 값을 지정한다. BEGIN{ FS="fs" } 이렇게 한 것과 같다.
-v var=val: 변수 var를 val로 지정한다. BEGIN{var=val} 한 것과 같다
-f file: awk 스크립트를 지정한다
--dump-variables[=file]: global 변수들의 이름과 값을 출력한다. file을 지정하지 않으면 현재 디렉터리의 awkvars.out 파일로 출력한다. 디버깅용으로 사용할 수 있다.
--re-interval: 정규표현식 중 인터벌을 사용할 수 있게 한다. {n,m}



IV. AWK Examples

앞에서 이론 공부를 했으니 이제 몇가지 예제를 보면서 익히는 게 좋을 것 같다. 우아한 것들로 골라봤다.

1. awk '$7 ~ /^[a-f]/'
7번 필드가 정규식 /^[a-f]/에 매칭된다면 출력한다.

2. awk '$7 !~ /^[^a-f]/{ print > “/proc/self/fd/2” }'
바로 앞의 예와 같은 패턴 매칭이지만 출력을 표준에러로 한다. "/dev/stderr" 를 대신 쓸 수 있다.

3. awk 'NF'
NF가 0(false)이 아니면 출력한다. 즉 빈행이 아니면 출력한다. 여기서 action statements는 생략됐으므로 디폴트인 { print $0 }가 실행됨은 이제 다들 아실거라 생각한다.

4. awk 'NF{ $0=cnt++" "$0}1'
NF가 0이 아니면 줄 앞에 cnt를 표시한 뒤 출력한다. 1이라는 숫자에는 의미가 없다. 단지 패턴에 0이 아닌 다른 숫자나 스트링이 오면 항상 true 이기 때문에 디폴트 액션이 실행된다.

5. awk '{ sub(/^[ \t]*/,""); print }'
표준 스트링 함수인 sub(pattern,replacement) 를 사용했다. 모든 패턴에 대해서 sub(/^[ \t]*/,"") 를 적용하며 이 함수는 레코드 자체를 수정하므로 리턴값을 받을 필요는 없다. 함수 의미를 풀면 정규식 ^[ \t]* 를 지우라는 뜻이다. 즉, leading 공백문자들을 삭제한다.

6. awk '{ gsub(/^[ \t]*|[ \t]*$/,"") }1'
이것은 앞선 예와 비슷한 기능이다. gsub() 함수는 sub의 global버전이라 할 수 있겠다. sub은 최초 매치만 substitution을 행함에 반해 gsub은 모든 매치들에 대해 substitution을 수행한다. 위 one-liner의 뜻은 모든 leading whitespace 캐릭터들 (^[ \t]*) 또는 (|) 모든 trailing whitespace 캐릭터들 ([ \t]*$)을 제거하라는 뜻이다. 그리고 맨 마지막에 1을 붙여서 디폴트 액션을 수행하게끔 하였다.

7. awk '!a[$0]++'
이것은 배열의 섭스크립트에 스트링도 넣을 수 있다는 점과 awk에서 변수나 배열은 초기화가 필요하지 않다는 점을 십분활용한 예다.
만약 현재 레코드가 처음 나온 레코드라면(현재 라인이 앞선 라인들과 중복되지 않은 라인이면) a[$0]의 값은 0이다. 그러므로 !a[$0]은 0이 아니다. true다. 패턴이 true이므로 디폴트 액션문이 실행되는 조건을 만족시킨다. 그러고 나서 a[$0]을 1 증가시켜서 (a[$0]++) 값이 1이 된다. 만약 나중에 똑같은 레코드가 들어왔다면, !a[$0]은 false가 돼서 출력은 되지 않을 것이다. 그래도 a[$0]++은 실행되므로 값이 증가된다. 결론적으로 이 one-liner의 역할은 중복된 라인을 제거하면서 똑같은 라인의 개수를 파악하는 것이다.

8. awk 'BEGIN{FS=""}{ for (i=NF;i>=1;i--) printf "%s",$i; print ""}'
우선 인풋이 들어오기 전에 BEGIN{} 블록을 실행한다. FS를 널스트링으로 바꿨다. FS 의 값 설정은 awk -F"" 로써 편리하게 할 수도 있다. FS가 널스트링이면 한개의 필드는 한개의 캐릭터에 대응된다. for 문에서 사용한 NF는 필드의 개수를 뜻하므로 i=NF는 마지막 필드를 가리키는 셈이다. for문을 돌면서 현재 i가 가리키는 필드를 printf문으로 출력한다. 즉 맨마지막 캐릭터부터 맨앞 캐릭터까지 역순으로 출력한다. 마지막 print "" 는 단지, 마지막에 ORS를 붙여주기 위함이다.

9. cat /usr/man/man1/awk.1 |grep '\(^\.SH\|^\.SS\)'|awk '/\.SS/{ $0 = "    "$0}{sub(".SH",""); sub(".SS", "")}1'
awk 맨페이지를 cat으로 읽은 뒤 타이틀을 뜻하는 .SH와 .SS 라인만 추려내 그 라인을 보기 좋도록 .SH와 .SS를 떼어내는 one-liner이다. 즉 맨페이지의 목차를 보여준다. 만약 맨페이지가 gzip 압축됐다면 cat 명령어를 gzip -cd 로 대체하면 된다.

10. awk 'NR==40001,NR==40100{ array[$3]++};END{ size=asorti(array,dest); for (i=1; i <= size; i++) {print dest[i], array[dest[i]]}}' /var/log/messages
messages 파일 중 40001번째 줄부터 40100번째 줄까지 읽고 세번째 필드의 출현 횟수를 기록한다. messages의 세번째 필드는 시각이다. 그러고 나서 모든 인풋이 소진되면 END블록이 실행된다. asorti 는 표준 스트링함수인데 array배열을 받아서 배열의 값대로 정렬한 뒤 결과를 dest 배열의 값에 넣고 인덱스는 1번부터 시작해 증가시킨다. 즉 dest배열은 시간순으로 정렬된 셈이다. 그리고 마지막 for문에 print dest[i], array[dest[i]] 로써 "시간  출현횟수" 형식으로 출력한다.

11.  awk 'END{ print NR}'
모든 인풋이 소진되고 END블록이 실행된다. NR의 값은 마지막 줄번호를 가리키므로 총 라인 수를 출력하는 셈이다.

12. awk 'BEGIN{ mysql="mysql -u rhdxmr --password=somepassword mydb" } { string1="\047Jaco Pastorius\047"; string2="\047Cha Cha\047"; print "insert into test values("string1","string2");"|mysql}'

이 예에서는 print I/O statement의 표준출력을 | 연산자로써 외부 프로그램의 표준입력에 주었다는 것이 주목할 점이다. 명령행에서 작은 따옴표를 넣으면 의도와 다르게 배시에서 파싱돼버리므로 octal value인 \047로 작은 따옴표를 표현했다. 그래서 MySQL에 입력된 쿼리문은 insert into test values('Jaco Pastorius','Cha Cha');다. 이 예에서 처럼 쿼리문의 일부를 변수로 대체시켜 상황에 따라서 다른 쿼리문을 생성할 수 있다.

13. awk 'length < 86'
length는 변수처럼 보이지만 원래는 표준 함수 length()이다. awk에서 유일하게 변수형태와 함수형태 모두 사용가능한 녀석이다. 이것은 어디까지 historical feature이므로 깊게 생각할 필요는 없다. length 는 length($0)와 같은 의미인데 이 one-liner는 한 레코드의 전체 길이가 86이하인 짧은 줄만 출력하라는 뜻이 된다.

14. awk '{ print $NF }'
NF는 현재 레코드의 총 필드의 개수를 의미하는데 이는 곧 마지막 필드가 몇번째 필드인지 가리킨다. 그러므로 print $NF는 마지막 필드를 출력하라는 의미이다.

15. awk '{  for(i=1; i<=NF; i++) A = A" "$i; print A; A = "" }'
i의 초기값으로 지정된 필드부터 마지막 필드까지 출력한다. for문의 i값에 처음 출력을 원하는 필드번호를 적으면 그 필드부터 마지막 필드까지 출력한다.

여기까지 먼길을 왔는데 AWK에 대한 설명은 이쯤에서 마치도록 하겠다. 조금 쉬었다 바로 SED가 무언지 보러 갈테니 아직 긴장을 풀지 마시길. 낄낄


출처 : http://rhdxmr.tistory.com/57
반응형

'OS > Linux' 카테고리의 다른 글

CENTOS 7에 XRDP 설치하기  (0) 2017.08.26
리눅스 백업 및 복구  (0) 2013.01.25
삼성 컴퓨터 유분투 설치기.  (0) 2012.02.06
rkhunter (리눅스 침입 탐지 사용하기)  (1) 2010.10.14
ps auxc 와 ps aux 결과 비교하기  (0) 2010.01.21

+ Recent posts