Index Skip Scan

분류없음 2008/12/03 09:16

엔코아의 자료입니다.

 

Index Skip Scan<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

오라클 9i에서 새로운 인덱스 액세스 메쏘드로 소개된 index skip scan을 소개합니다.

 

1. Index Skip Scan의 개념

인덱스를 경유한 테이블 액세스의 속도를 빠르게 하기 위해서 오라클 9i index skip scan이라는 새로운 인덱스 스캐닝 방식을 제공한다. Index skip scan의 데이터 access 방식을 한마디로 정리하면,

  l         관련 테이블(컬럼)의 데이터 분포에 대한 통계 정보가 제대로 만들어져 있고,

    l         selectivity가 낮은 칼럼 + selectivity가 높은 칼럼으로 구성된 복합인덱스(concatenated index)를 가진 어떤 테이블 데이터를 질의할 때

  l         선행 칼럼에 대한 선택 조건은 주지 않고, selectivity가 높은 칼럼의 선택 조건만 where 구문에 명시하면 기존에는 인덱스 선행 칼럼에 대한 조건이 명시 되지 않았기 때문에 전체 테이블에 대한 full scan이 발생했지만, 오라클 9i index skip  scan이란 새로운 인덱스 스캐닝 방식으로 빠른 수행 속도를 보장한다

간단한 sample을 들자면,

        sample table

테이블명:  BALANCE  잔고테이블

BRANCH_NO

VARCHAR2(3)

지점번호 001 ~ 100

ACCNT_NO

NUMBER

10자리 예금별 일련번호

BALANCE

NUMBER

 

        index
인덱스: BALANCE_IDX1 = (BRANCH_NO, ACCNT_NO )

        query
SELECT * FROM   BALANCE WHERE  ACCNT_NO = 1000000031;

        plan
TABLE ACCESS BY INDEX ROWID        COPYX
                         
INDEX SKIP SCAN              COPYX_IX1

 

이전 버전의 오라클에서 인덱스의 선행 칼럼인 지점번호에 대한 조건이 주어지지 않은 상태에서 계좌번호만으로 데이터를 조회하려고, 사용한 위와 같은 쿼리는 인덱스를 경유해서 데이터를 액세스하지 않고 Table Full Scan을 해 왔던 것을 우리는 잘 알고 있다.   이를 때 우리는 강제로 인덱스를 통한 조회를 유도하기 위해서 우리는 선행칼럼(지점번호)에 대한 정보를 알고 있는 경우 다음과 같이 subquery를 사용해서 상품 종류에 대한 정보를 제공하거나 프로그램에서 상수로 이 조건을 직접 공급시켜서 인덱스를 통한 테이블 액세스를 유도해 왔다. ( 대용량 데이터 베이스 솔루션 2 )

SELECT *
  FROM  BALANCE
 
WHERE BRANCH_NO IN ( SELECT BRANCH_NO FROM BRANCH )
  AND ACCNT_NO = 10000031

그러나 이 경우 복합인덱스를 구성하고 있는 선행칼럼 개수가  많아질 때 (IN으로 여러 칼럼 조건이 공급될 때), 데이터 베이스가 주어진 칼럼들의  곱한 각 경우의 수 만큼의 equal match를 시도하게 되는 (실제 데이터는 존재하지 않으나 index root를 뒤져봄) 경우의 문제와 이 조건을 subquery로 공급하지 못하고 상수로 코딩해야 하는 경우 프로그램 변경등의 부담이 있어 왔다.
 
이에 대한 대안으로 제시된 index skip scan은 어떤 방식으로 인덱스를 액세스하는 것일까? 오라클이 간략하게나마 소개하고 있는 개념은 scan단위가 몇 개의 논리적인 sub-index로 나뉜다는 것인데 위의 예제의 수행 과정을 풀어보면, 만약 실 데이터가 두개의 지점번호만  가진 경우( 001 002) 가졌다고 가정하면 BALANCE_IX1 인덱스는 로지컬 하게 다음과 같이 두개의 sub-index로 나뉘어져서 스캔된다고 볼 수 있다. 즉 첫번째 sub-index 001을 선두 값으로 갖고, 다른 하나의 sub-index 002을 선두 값으로 갖는 파트라고 생각할 수 있다. 이것은 개념적으로는

  SELECT *
    FROM BALANCE 
    WHERE BRANCH_NO = ‘001’
    AND ACCNT_NO = 100000031
    UNION ALL 
    SELECT *
    FROM BALANCE
    WHERE BRANCH_NO = ‘002’
    AND ACCNT_NO = 100000031

이라는 조건으로 차례대로 실행된다고 볼 수 있다. 이것을 그림으로 표현해 보면 다음과 같다.

[
그림1]
 <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

그러나 도대체 sub-index는 어떤 단위로 만들어지고, scan block들을 어떤 순으로 access하는 것일까? Index skip scan index block access 방식을 확인해 보기 위해서 몇 가지 실행event dump를 확인한 결과 Skip scanning은 복합 칼럼인덱스를 로지컬하게 작은 단위의 sub-index로 분할해서 동작함을 알 수 있는데, logical sub-index의 개수는 선행 컬럼의 distinct value 개수와 밀접하게 관련 있음을 알 수 있다. 물리적으로 index skip scan이 발생할  때 데이터베이스는 우선 인덱스의 root 블록을 읽은 후,  branch block을 차례로 access하면서 concatenated 되어 있는 복합인덱스 구성 value로 하위의 leaf block을 읽을지 말지 결정한다.  그러므로 논리적인 개념의 sub-index라는 것은 실제적으로는  branch block distinct value단위라고 볼 수 있을 것이다. 따라서 index skip scan은 전체 인덱스 블록을 모두 scanning하는 index fast full scan보다는 적인 수의 block access하게 되고, 칼럼 값을 바로 =로 공급한 (IN으로 공급한 경우) 보다는 많은 수의 블록을 읽게 된다. 실제 수행 속도의 경우도 첨부한  테스트 결과 집계 경우와 같이 시스템의 성격에 따라서 acceptable한 수준이라고 할 수 있다

[1] Index Skip Scan 수행속도 테스트

IN으로 조건을 공급한 경우

index skip scan

테스트 조건

0.3 sec

0.8 sec

대상데이터: 2000000

인덱스구성: col1+col2+col3

선행칼럼distinct개수: col1(100) * col2(20) *

선택칼럼: all unique in group

0.4 sec

1.2 sec

1   sec

1.8 sec

 

2. Index Skip Scan의 활용

Index skip scan이라는 새로운 인덱스 액세스 메쏘드는 IN으로 선행칼럼의 조건을 모두 공급해주어야 했던 튜닝 부담을 어느 정도 경감시켜주지만 최고 query 성능을 보장하지는 못한다. 그리고 index skip scan을 믿고 사용하기에는 어느 정도 불안정한 요소가 있는데 우선은 첨부화일의 테스트 결과표에서 보여주는 바와 같이 query의 유형에 따라서 index skip scan이 발생하는 경우가 어느 정도 제한적이며, 임의로 힌트를 주어서 index skip scan을 강제하거나 막을 수 없기 때문에 데이터 분포에 대한 확신이 있을 때에만 사용할 수 있다.
  , 선행칼럼의 조건을 입력 받지 않고도 어느 정도의 수행속도를 보장한다는 일면에서는, 인덱스의 구조나 엑세스 원리에 대한 기본적인 이해가 없는 EUC 환경의 사용자가 임의의 쿼리를 수행하는 경우에도 어느 정도의 수행속도를 보장할 수 있고, 인덱스 구성시에 자주 사용되는 칼럼과 selectivity가 높은 칼럼중에서 어느 것을 선두로 둘 것이냐의 의사결정에 어느 정도의 고려 사항이 된다고 하겠다.

----------------------------------------------------
[참조]
  query의 유형에 따라서 skip scan의 발생 양상이 예상과 틀린 경우도 많아서 몇 가지 유형의 query에 대한 검증  skip scan에 대해서 일반적으로 가지는 의문점을 테스트한 결과를 첨부함.


[ITBANK진순쌤, 정보보안전문가] [펌]Index Skip Scan
Posted by Bees

1.세션

Tools > Preferences > Oracle > Connection > Session Mode
- Single session (선택)

2.접속유지
Tools > Preferences > Oracle > Connection
- Check connection (체크)

3.사용자 이름/비밀번호 저장
Tools > Preferences > Oracle > Logon History > Definition
- Store with password (체크)

4.작업파일 백업
Tools > Preferences > Files > Directories > Test scripts
- E:\PLSQLDeveloper\test (입력)

Tools > Preferences > Files > Directories > SQL scripts
- E:\PLSQLDeveloper\sql (입력)

Tools > Preferences > Files > Directories > Command files
- E:\PLSQLDeveloper\command (입력)
Posted by Bees

4.1 북마크 플러그인(Bookmark Plugin) 설치

 이클립스의 북마크는 Visual Studio의 북마크보다 약간 불편하다. 북마크를 생성할 때마다 이름을 입력해야 하며 Quick하게 이동하기도 불편하게 되어있다. 이러한 기능을 보강하고자 나온 것이 북마크 플러그인이다. http://wimy.com/tt/106에서 내용을 찾아볼 수 있다.

 http://etc.to/eclipse_bookmarks_plugin에 보면 아래와 같은 기능 설명과 업데이트 경로가 나온다.

I just created my second Eclipse plugin which adds several bookmark methods to the editor. The "default" bookmark methods of Eclipse ask for a name and this is often not very useful. The code here adds bookmarks a la "Borland" and bookmarks a la "JCreator". The code has the following options which can all be bound/rebound with the keys dialog under the "Edit" category:

  • Add a numbered bookmark at the cursor: Alt+[digit]. This creates a quick bookmark with the specified number using a "single" keypress. Only one bookmark of the given number can be present in the workspace. Setting the same number bookmark again will clear the earlier instance.
  • Goto a numbered bookmark: Alt+Shift+[digit]. Moves to the bookmark as it was set using Alt+[digit].
  • Toggle Bookmark: Ctrl+B. This drops an unnamed bookmark at the current location. Pressing Ctrl+B again releases the bookmark at that location again. This is often used with "Goto next bookmark" and "Goto previous bookmark".
  • Goto next bookmark in file: Ctrl+N. This locates the next bookmark in the current file and moves there.
  • Goto previous bookmark in file: Ctrl+P. This locates the previous bookmark in the current file and moves there. warning: the Ctrl+P binding is a suggestion only; since Ctrl+P is currently assigned you must add your own key binding using Window -> Preferences -> General -> Keys.

I'll be posting the source of the plugin later on; the plugin can be installed using the update site

http://eclipse.etc.to/updates/

 설치 방법은 아래와 같이 메뉴에서 Install/Update를 이용하면 된다.

설정3.PNG

<Plugin 설치메뉴>

 

 위 메뉴를 클릭하면 Install/Update 다얼로그가 표시되는데 Search for new features to install 항목을 선택하여 Next 버튼을 누르면 아래와 같은 화면이 표시된다.

설정4.PNG

<새로운 사이트 추가>

 우측 상단의 New Remote Site를 클릭하고 다이얼로그를 위와 같이 체운 후 OK 버튼을 누르면 etc.to 사이트가 추가된다. 북마크 플러그인을 설치하기위해서는 Java Development Tools(JDT)을 설치해야 하므로 Europa Discovery Site 항목을 체크한 뒤에 Finish 버튼을 클릭한다.

 잠시 시간이 지나면 아래와 같은 검색 결과가 표시되는데 Java Development Tools를 체크하여 Next 버튼을 누르면 JDT가 설치된다.

설정5.PNG

<JDT 설치화면>

 JDT의 설치가 끝나면 동일한 방법으로 etc.to 항목을 클릭하고 검색결과로 나온 Eclipse Editor Extentions를 설치하면 정상적으로 완료된다. 북마크 키에 대한 설정은 위의 단축키 설정을 참고하자.

Posted by Bees

가끔씩은 이클립스 언어를 변경해서 보고 싶을때가 있습니다.

도움말이라던지 메뉴가 알송달송할때요.

 

실행시

\\eclipse.exe  -nl ko_KR

\\eclipse.exe  -nl en_US

Posted by Bees

정규 표현식

분류없음 2008/10/20 21:47

정규 표현식

[Illustration]

들어 가기 전에: 정규 표현식은 문맥 민감(context sensitive)한 탐색을 하거나, 텍스트를 수정할 때 매우 많이 쓰인다. 정규 표현식은 좋은 에디터나, 파서 프로그램과 언어세 쓰인다.




들어 가는 글

정규 표현식이 emacs나 vi같은 에디터나 grep/egrep 과 awk, perl , sed 같은 프로그램에서 사용되는 것을 볼 수 있다..

정규 표현식은 향상된 문맥민감(context sensitive) 탐색이나 텍스트의 수정 등에서 사용된다. 정규 표현식은 텍스트의 문자열과 매치되는, 형식이 아주 잘 갖춰진 표현이다.

필자는 몇 년 전에 정규 표현식을 쓰는 사람을 보고서 정규 표현식에 빠져 들게 되었다. Text를 입력하는 일과 수정하는 일은 보통 많은 시간이 걸리게 되게 마련인데, 그 사람은 몇 초만에 일을 하고 말았다. 화면에 있는 표현식을 봤을 때 이해할 수는 없었다. 표현식은 점(.)과 슬래쉬(/)로 시작하고 몇몇 문자의 조합으로 이루어져 있었다. 그때부터 정규 표현식이 어떻게 돌아가는지 배우기 시작했고, 곧 정규 표현식이 어렵지 않다는 것을 알았다. 단순히 간단한 문법 규칙들로 이루어 졌다는 것을 알았다.

정규 표현식은 유닉스 환경에서 매우 많이 사용되고 있지만, '표준 정규 표현 언어'는 있지 않다. 약간 변형된 표현식이 많다. 예를 들어 'grep' 프로그램에도 'grep'과 'egrap'의 두가지가 있다. 위의 두 프로그램은 약간 다른 정규 표현식을 사용한다. perl은 가장 많은 정규 표현식을 가지고 있다. 다행이도 모든 표현식은 같은 원리를 가지고 있다. 한번만 이런 기본적인 원리를 이해하고 나면, 서로 다른 표현식이라도 쉽게 배울 수 있을 것이다.

이 기사에서는 기본적인 것들만 소개할 것이고, 나머지는 독자들이 직접 매뉴얼 페이지를 보면서 서로 다른 프로그램에 대해서 배울 수 있다.

간단한 예제

다음과 같은 회사의 전화번호 리스트가 있다고 가정을 해보자.

Phone Name  ID
...
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...

500명의 직원을 가진 회사이다. 위의 파일은 단순히 아스키 코드로 되어있는 Text 파일이다. 전화번호가 1로 시작되는 사람은 1번 건물에서 근무하는 사람들이다. 어떤 사람들이 1번 건물에서 근무하는지 알고 싶으면 어떻게 하여야 할까?

다음과 같은 정규 표현식이 그 답을 말해 준다 :
grep '^1' phonelist.txt
or
egrep '^1' phonelist.txt
or
perl -ne 'print if (/^1/)' phonelist.txt

위의 표현식은 첫 글자가 1인 모든 줄을 찾으라는 표현식이다. "^"는 줄의 시작을 나타낸다. 즉 첫 글자가 1인 줄을 찾으라는 것이다.

The syntax rules

한 문자 패턴

기본적인 정규 표현식은 한 문자 패턴(single-character pattern)으로 이루어져 있다. 정확히 한 문자와 맞는 경우를 말한다. 한 문자 패턴의 예는 위에 있는 1을 찾는 문제이다. 한 문자와 필적을 한다.

다른 한 문자 패턴의 예는 다음과 같다:
egrep 'Kerry' phonelist.txt

위의 패턴은 단순히 한 문자 패턴으로 구성되어 있다.( K,e.. 와 같은 문자)

문자들은 함께 그룹화 되어 집합이 될 수 있다. 집합은 '['로 시작해서 ']'로 끝나고, 그 사이에 문자들이 있는 것을 말한다. 집합 또한 한 문자 패턴이다. 집합 안에 있는 한 문자 만이 텍스트의 탐색에서 짝을 이룰 수 있다. 예를 들어 :

[abc]    a, b 혹은 c가 매치되는지 보는 한 문자 패턴이다.  

[ab0-9] a, b 혹은 숫자에 해당되는지를
나타내는 한 문자 패턴이다.

[a-zA-Z0-9\-] 대문자, 소문자, 숫자, 음수 기호(-)의 매치를
나타내는 한 문자 패턴이다.

다음과 같이 해보자:
egrep '^1[348]' phonelist.txt

위의 표현식은 13, 14, 18로 시작되는 줄을 탐색하게 된다.

대부분의 아스키 문자들은 매치되는지를 알아 보기 위해서 쓰지만 특별한 의미를 나타내는 아스키 문자들도 있다. 예를 들어 '['는 집합의 시작을 나타낸다. '-'는 범위를 나타내는 특별한 의미를 가진 문자이다. 이러한 문자를 의미없이 쓰려면 문자 앞에 '\'를 붙이면 된다. [a-zA-Z0-9\-]가 이러한 예이다. 일부 변형된 정규 표현식에서는 약간 다른 표현이 쓰인다. 특별한 문자가 '\'와 함께 시작되는 정규 표현식을 쓰는 경우도 있다. 이 경우 일반적인 아스키 문자를 나타내기 위하여 '\'를 제거해야 한다.

점(.)은 매우 특별한 의미를 가진 특수 문자이다. newline 문자를 제외한 모든 문자를 나태낸다. 예를 들어 :

grep '^.2' phonelist.txt
or
egrep '^.2' phonelist.txt

위의 표현은 두 번째 문자가 2이고, 첫 문자는 아무 문자나 나오는 줄을 탐색하는 표현이다.

집합의 처음을 '['로 사용하지 않고 '[^'로 사용하면 역집합을 나타낸다. '['뒤에 있는 '^'는 줄을 시작을 나타내지 않고 역을 나태낸다.

[0-9]    0과 9사이의 숫자를 나타내는 한 문자 패턴이다. 
[^0-9] 숫자가 아닌 문자를 나타낸다.
[^abc] a,b,c 문자가 아닌 모든 문자를 나타낸다.
. 점(.)은 newline 문자가 아닌 모든 문자를 나타낸다.
즉 [^\n]와 같다.
1로 시작되지 않는 줄을 찾기 위해서 다음과 같이 쓸 수 있다 :

grep '^[^1]' phonelist.txt
or
egrep '^[^1]' phonelist.txt

Anchors

'^'가 줄의 시작을 나타낸다고 위해서 배웠다. Anchor는 정규 표현식에서 문자의 위치를 나타내거나 텍스트에 없는 문자를 나타내는 특별한 문자이다.

^  줄의 시작을 나타낸다. 
$ 줄의 끝을 나타낸다.

phonelist.txt에서 회사 ID 번호가 567인 것을 찾기 위해서 다음과 같이 쓸 수 있다 :

egrep '567$' phonelist.txt

위는 줄의 끝이 567인 줄을 찾는다.

Multipliers

Multiplier는 한 문자 패턴이 텍스트에서 얼마나 자주 반복되는지를 결정한다.

descriptiongrepegrepperlvivimvileelvisemacs
0번 이상 * * * * * * * *
1번 이상 \{1,\} + +   \+ \+ \+ +
0번 혹은 1번 \? ? ?   \= \? \= ?
n에서 m 번 \{n,m\}   {n,m}       \{n,m\} \{n,m\}

Note: 다양한 VI 프로그램들은 위와 같은 작업을 하기 위해서 매직 옵션을 두고 있다.

전화 번호 리스트에서의 예:

....
1248 Kate 634
....
1548 Kerry 534
....

1로 시작하고, 뒤에 숫자가 몇 개 오며, 적어도 하나의 공백이 있고, K로 시작하는 이름을 찾기 위해서는 다음과 같이 하면 된다.

grep '^1[0-9]\{1,\} \{1,\}K' phonelist.txt
또는 *와 [0-9]와 공백을 반복하여 :
grep '^1[0-9][0-9]* *K' phonelist.txt
또는
egrep '^1[0-9]+ +K' phonelist.txt
또는
perl -ne 'print if (/^1[0-9]+ +K/)' phonelist.txt

'*'는 바로 앞 한 문자의 반복을 나타낸다. 즉 "23*4"는 "2와3, 아무 문자나 여러 개, 4"를 나타내지 않는다.(이의 경우 "23.*4"이다.) 위의 식은 "한 개의2, 여러 개의 3, 한 개의4" 를 나타낸다.

또한 '*'는 게걸스럽다는(greedy) 걸 알아야 한다. 즉, '*'는 최대한 오른쪽으로 확장을 한다.

The expression ^1.*4
위의 식은 다음 줄 전체와 매치가 된다.
1548 Kerry 534
시작부터 4로 끝나는 걸 의미 하지, 154와 매치되지는 않는다.

grep에서는 별로 중요하지 않지만, 에디트를 하거나 대치를 할 경우 매우 중요하다.

Parentheses as Memory(메모리로서의 괄호?)

'Parentheses as Memory' 구조는 정규 표현식의 매치 방법은 변하지 않지만, 괄호로 묶인 부분은 기억되었다가 뒤에 쓰일 수 있다.

기억된 부분은 변수를 이용해서 뒤에 이용될 수 있다. 첫 번째 'Parentheses as Memory' 구조는 1 번 변수를 통해서 이용되고, 두 번째 'Parentheses as Memory' 구조는 2번 변수를 써서 이용된다.

프로그램 이름parentheses syntax변수 문법
grep \(\) \1
egrep () \1
perl () \1 or ${1}
vi,vim,vile,elvis \(\) \1
emacs \(\) \1

예:

 식  [a-z][a-z] 은 두 개의 소문자와 매치된다.  

이제 우리는 'otto'와 같은 텍스트를 찾기 위하여 변수를 쓸 수 있다.

egrep '([a-z])([a-z])\2\1'

변수 \1은 'o'를 저장하고 있고, \2는 't'를 저장하고 있다.

'anna'와 같은 이름과는 매치되지만, 'yxyx'와 같은 이름과는
매치되지 않는다.

'Parentheses as Memory' 구조는 'otto'나 'anna'와 같은 이름을 찾는데는 많이 쓰이지 않고, 대신 에디트를 하거나, 대치(substitution)을 하는데 많이 쓰인다.

Text를 편집하면서 정규 표현식 쓰기

에디트를 하기 위해서 vi나 emacs혹은 perl과 같은 것을 사용해야 한다.

emacs에서는 M-x query-replace-regexp 혹은 query-replace-regexp 버튼을 사용사용한다. 또는 replace-regexp 명령을 사용할 수 있다. query-replace-regexp만 interactive하고, 나머지는 그렇지 않다.

vi에서는 대치 명령이 %s/ / /gc이다. 여기서 '%'는 '파일 전체'를 나타낸다. 아니면 적당한 범위를 지정해 줄 수도 있다. vim에서는 shift-v를 친 후에 대치하기를 원하는 부분을 지정해 줄 수 있다. 여기서는 vim에 대한 자세한 설명을 해 줄 수 없다. 메뉴얼을 스스로 보라. 'gc'는 interactive한 것을 나타낸다. s/ / /g는 interactive하지 않음을 나타낸다.

interactive하다는 것은 매치되는 것을 만날 때마다, 대치를 할 것인지 안 할 것인지 물어 보는 것을 말한다.

perl에서는 다음과 같이 사용할 수 있다.

perl -pe 's/ / /g' 

몇 가지 예를 보자. 위에 나온 회사에서 전화 번호가 바뀌어 1과 2로 시작하는 번호는 두번째 위치에 2가 추가 되었다. 예를 들어 1423은 14223으로 되었다.

예전의 리스트 :

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
1248 Kate 634
1423 Tony 567
2567 Peter 435
3567 Alice 535
1548 Kerry 534
...

다음과 같이 하면 된다:

vi:    s/^\(1.\)/\12/g
emacs: ^\(1.\) replaced by \12
perl: perl -pe 's/^(1.)/${1}2/g' phonelist.txt

새로운 리스트는 다음과 같을 것이다.

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

Perl은 메모리 변수를 \1부터 \9까지 사용하므로 \12는 텅 비어있는 12번째 변수를 참조하고 있다. 이러한 문제를 해결하기 위하여 단순히 ${1}을 사용하면 된다.

위의 리스트는 아직도 약간 정렬이 잘못되어 있다. 어떻게 하면 고칠 수 있을까? 5번째 위치에 공백이 있는지 없는지 검사를 하고, 공백이 없으면 하나의 공백을 집어 넣으면 된다.

vi:     s/^\(....\) /\1  /g
emacs: '^\(....\) ' replaced by '\1 '
perl: perl -pe 's/^(....) /${1} /g' phonelist.txt

이제 리스트는 다음과 같을 것이다.

Phone Name ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

만약에 수작업을 하다가 줄의 시작에 몇 개의 공백을 입력했다면 공백들을 어떻게 제거할 수 있을까?

Phone Name  ID
...
3412 Bob 123
3834 Jonny 333
12248 Kate 634
14223 Tony 567
2567 Peter 435
3567 Alice 535
15248 Kerry 534
...

다음과 같이 하면 된다.
vi: s/^ *// (There is 2 spaces as we do not have a +)
emacs: '^ +' replaced by the empty string
perl: perl -pe 's/^ +//' phonelist.txt

소스 코드를 작성하면서 temp라는 변수와 temporary라는 변수를 사용하고 있다고 가정을 하자. 그런데 temp를 counter로 바꾸고자 한다. 단순히 temp가 counter로 바뀌면 temporary는 counterorary로 바뀌어 버린다.

정규 표현식은 이런 일을 할 수 있다. 단순히 temp([^o])를 counter\1로 바꾸면 된다. 즉, tempo가 아니라고 말해주면 된다. (크기의 경계을 두는 방법도 있지만, 우리는 이러한 방식의 패턴을 배우지 않았다.)

Regular expressions can do it. Just replace temp([^o]) with counter\1. That is, temp and not the letter o. (An alternative solution would be to use boundaries but we have not discussed this kind of anchoring pattern.)

이 글을 읽고 흥미를 느꼈으면 하는 바램이다. 이제 당신은 좋아하는 에디터의 맨 페이지나, 메뉴얼을 보면서 더욱 자세하게 배워야 한다.

또한 위에서 말한 경계나 "or"를 나타내는 특별한 문자도 있다.

재미있게 보셨나요? 직접 해보세요..:)

Posted by Bees

Perl Tip

분류없음 2008/10/20 19:22
    목 차

  1. 3000을 3,000으로 변경
  2. 문자열에서 특정위치 문자의 아스키 코드를 알아내는 방법
  3. 입력 받는 값이 숫자로만 되어 있는지 문자로만 되어있는지를 아는 방법
  4. 절대 경로가 모두 명시된 파일 이름에서 파일 이름만 추출해내는 방법
  5. 한글문자열을 일정한 길이만큼 보여줄 때 마지막에 한글이 잘리지 않게하는 방법
  6. 소숫점 처리 (자리수, 올림, 내림)
  7. 대몬자 -> 소문자, 소문자 -> 대문자
  8. E-Mail 주소 Check
  9. 데이타 구조
  10. Date & Time 출력

  1. 3000을 3,000으로 변경 <br /> {} while $a =~ s/(\d+)(\d{3})/$1,$2/;<br />
  2. 문자열에서 특정위치 문자의 아스키 코드를 알아내는 방법 <br /> $s = '싱글벙글 아줌마 투덜투덜 아저씨 아줌마가 펼치는 꿈속같은 이야기..';<br /> my ($target) = $s =~ /^.{20}(.)/;<br /> #my $target = substr $s, 20, 1, 0;<br /> $hex = uc unpack 'H*', $target;<br /> print $hex;<br />
  3. 입력 받는 값이 숫자로만 되어 있는지 문자로만 되어있는지를 아는 방법 <br /> $isNumber = $s =~ /\d/ ? 1 : 0;<br />
  4. 절대 경로가 모두 명시된 파일 이름에서 파일 이름만 추출해내는 방법 <br /> ♥예를 들어 인수로 /home/foobar/xyz.tar.gz가 주어진다면 결과값으로<br /> ♥xyz.tar.gz를 구하고자 합니다.<br /> <br />$path = '/home/foobar/xyz.tar.gz';<br /> my ($filename) = $path =~ m&amp;lt;([^/\\]+)$&amp;gt;;<br /> <br />#!/usr/bin/perl -w<br /> <br />use File::Basename;<br /> <br />foreach ( '/home/c/fred.c', '/home/c/fred.orig.c', '/home/c/fred' ) {<br /> ($name, $dir) = fileparse($_, ('\.*'));<br /> print "dir '$dir' name '$name'\n";<br /> }<br /> <br />패스중 디렉토리 부분은 $dir에, 실제 이름은 $name에 들어갑니다.<br /> <br />결과<br /> ----<br /> <br />dir '/home/c/' name 'fred.c'<br /> dir '/home/c/' name 'fred.orig.c'<br /> dir '/home/c/' name 'fred'<br /> <br /><br /> 확장자까지 얻으려면 루프를 아래와 같이 써줍니다.<br /> <br />foreach ( '/home/c/fred.c', '/home/c/fred.orig.c', '/home/c/fred' ) {<br /> ($name, $dir, $ext) = fileparse($_, ('\.[^.]*'));<br /> print "dir '$dir' name '$name' ext '$ext'\n";<br /> }<br />
  5. 한글문자열을 일정한 길이만큼 보여줄 때 마지막에 한글이 잘리지 않게하는 방법 <br /> $subject = '싱글벙글 아줌마 투덜투덜 아저씨 아줌마가 펼치는';<br /> $max_length = 30;<br /> <br />if ( length $subject &amp;gt; $max_length ) { # 길이가 길면<br /> $subject = substr $subject, 0, $max_length;<br /> chop $subject if ($subject =~ y/[\xA1-\xFE]//) %2 != 0; # 2바이트문자 처리<br /> }<br /> <br />print $subject;<br /> <br />
  6. 소숫점 처리 (자리수, 올림, 내림) <br /> 코드<br /> --------------------------------------------------------------<br /> $data="3.141592654";<br /> <br />$round = sprintf("%.2f",$data);<br /> print "Round : $round\n\n";<br /> --------------------------------------------------------------<br /> <br />결과<br /> --------------------------------------------------------------<br /> Round : 3.14<br /> --------------------------------------------------------------<br /> <br />서비스 하나더 (올림,내림)<br /> <br />코드<br /> --------------------------------------------------------------<br /> use POSIX;<br /> $ceil = ceil(3.5);<br /> $floor = floor(3.5);<br /> <br />print "올림 : $ceil\n";<br /> print "내림 : $floor";<br /> --------------------------------------------------------------<br /> <br />결과<br /> --------------------------------------------------------------<br /> 올림 : 4<br /> 내림 : 3<br /> --------------------------------------------------------------<br />
  7. 대문자 -> 소문자, 소문자 -> 대문자 <br /> 코드<br /> ===================================<br /> $UPPER = "ABCDEFG";<br /> $lower = lc($UPPER);<br /> print "$lower";<br /> <br /><br /> 결과<br /> ===================================<br /> abcdefg<br /> <br /><br /> 보너스 하나더 (소문자 &amp;gt;&amp;gt; 대문자 )<br /> ===================================<br /> uc( )<br /> <br /> 또는 <br /> <br />$str = $lower = $upper = 'Hello, Perl!';<br /> <br />$lower =~ tr/A-Z/a-z/;<br /> $upper =~ tr/a-z/A-Z/;<br />
  8. E-Mail 주소 Check <br /> print &amp;amp;isValidEmailAddress('vivianchow.mailinglist.admin@hk.net.com');<br /> sub isValidEmailAddress {<br /> my $add = lc shift;<br /> return $add =~ /^[a-z0-9-_.]+\@\[?[a-z0-9-_]+(?:\.[a-z0-9-_]+){1,4}\[?$/ ? 1 : 0;<br /> }<br />
  9. 데이타 구조 <br /> 안녕하세요 ?<br /> perl은 환상적인 데이타 구조가 가능합니다.<br /> 예를들자면..<br /> my $info_db = {<br /> accplus =&amp;gt; {<br /> '이름' =&amp;gt; '전창훈',<br /> '설명' =&amp;gt; '본인',<br /> '친구들' =&amp;gt; [qw(shakalis circuit)]<br /> },<br /> shakalis =&amp;gt; {<br /> '이름' =&amp;gt; '김연수',<br /> '설명' =&amp;gt; '창훈이의 여자친구',<br /> '친구들' =&amp;gt; [qw(circuit)]<br /> },<br /> circuit =&amp;gt; {<br /> '이름' =&amp;gt; '박종명',<br /> '설명' =&amp;gt; '창훈이의 학교동창',<br /> '친구들' =&amp;gt; [qw(accplus shakalis)]<br /> },<br /> };<br /> 이런식으로 자료를 만들고<br /> <br />my $info_id = 'accplus';<br /> print "$info_id($info_db-&amp;gt;{$info_id}-&amp;gt;{'이름'})의 친구들은 =";<br /> for (@{$info_db-&amp;gt;{$info_id}-&amp;gt;{'친구들'}}) {<br /> $_ = $info_db-&amp;gt;{$_};<br /> print " $_-&amp;gt;{'이름'} ($_-&amp;gt;{'설명'})";<br /> }<br /> print "입니다\n";<br /> <br />이렇게 사용할 수도 있습니다.<br /> 한번 $info_id를 'shakalis'나 'circuit'로 바꾸어서 사용해 보세요<br /> <br />그러나 이러한 기법은 perl 프로그래머가 래퍼런스를 구사할 수 있을때<br /> 발휘되는데...<br /> 이런게 힘드시면 단지 lol (list of list)만 이해하셔서 2차원 배열만<br /> 사용하셔도 됩니다.<br /> <br />이것은 man perllol 하면 나오는데.. 이것은 정의는<br /> my @lol = (<br /> [1,2,3,4,5,6],<br /> [10,11,12,13,14,15],<br /> [20,21,22,23],<br /> );<br /> 이렇게 하시고, 사용방법은<br /> print $lol[2][2]; &amp;lt;-- 이렇게 하면 '22'가 print 됩니다. (0부터 시작)<br /> <br />즉 대괄호가 배열의 주소를 지정시켜주는 역할을 합니다.<br /> 역시 레퍼런스 개념이죠. 좀더 자세한 것은 man perldata하면 보실 수<br /> 있습니다.<br /> <br />
  10. Date & Time 출력 <br /> #!/usr/bin/perl<br /> <br />#####################################################################<br /> <br />$time_type="datetime"; # 원하는 출력형태를 지정하세요.<br /> <br />($second, $minute, $hour, $date, $month, $year, $weekday, $yearmonth,<br /> $Isdst) = localtime(time);<br /> $year_2 = $year + 1900; $month = $month + 1;<br /> @dayname = ('일','월','화','수','목','금','토');<br /> if($month &amp;lt; 10) { $month = "0$month"; } if($date &amp;lt; 10) { $date = "0$date";<br /> }<br /> if($minute &amp;lt; 10) { $minute = "0$minute"; }<br /> if($second &amp;lt; 10) { $second = "0$second"; }<br /> if($hour &amp;gt; 12) { $hour_2 = $hour; $hour = $hour - 12; $ampm = "PM"; } else<br /> { $hour_2 = $hour; $ampm = "AM"; }<br /> if($hour &amp;lt; 10) { $hour = "0$hour";}<br /> if($hour_2 &amp;lt; 10) { $hour_2 = "0$hour_2";}<br /> <br />#####################################################################<br /> <br />if($time_type eq "datetime") { $result = "$year/$month/$date<br /> ($dayname[$weekday]) $ampm $hour:$minute:$second"; }<br /> # ex. 98/01/01 (목) AM 00:00:00<br /> <br />if($time_type eq "dateonly") { $result = "$year/$month/$date<br /> ($dayname[$weekday])"; }<br /> # ex. 98/01/01 (목)<br /> <br />if($time_type eq "datetime4") { $result = "$year_2/$month/$date<br /> ($dayname[$weekday]) $ampm $hour:$minute:$second"; }<br /> # ex. 1998/01/01 (목) AM 00:00:00<br /> <br />if($time_type eq "dateonly4") { $result = "$year_2/$month/$date<br /> ($dayname[$weekday])"; }<br /> # ex. 1998/01/01 (목)<br /> <br />if($time_type eq "ymd") { $result = "$year_2/$month/$date"; }<br /> # ex. 1998/01/01<br /> <br />if($time_type eq "ymdhms") { $result = "$year_2/$month/$date<br /> $hour_2:$minute:$second"; }<br /> # ex. 1998/01/01 13:12:12<br /> <br />#####################################################################<br /> <br />print "$result \n";<br /> <br />#####################################################################<br />
Posted by Bees
TAG Perl
UNIXhelp 홈페이지 작업을 하다가, 
거의 다 끝나가는 상태인지라, 이제 색인작업을 하는데,
각 페이지의 "Index"라는 문자열을 모두 "색인"으로 바꾸어야 될 필요성이
생겼지요.

즉, a.html ... z.html 파일 안에 있는 모든 "Index"라는 문자열을
"색인"이라는 문자열로 바꾸어야 되는데, 이걸 일일이 각 파일을 열고,
문자열 바꾸기를 한다는 것이 여지간히 번거로운 작업이 아니지요.

분명 보다 편한 방법이 있을 진데,... 하면서 생각하다가,
얼핏 생각난 것이 sed 였지요. 사용법을 몰라 못 쓰고 있었던 것을
이참에 한번 배워보자 해서 "나중에 시간 날때 읽어야지"하면서,
저장해둔 글을 오늘에서야 읽게 되었습니다. (한글이었다면,
그날 당장 읽었겠지요. 도통 딸리는 영어 실력인지라, 큰마음 먹어야지
읽을 수 있기 때문에. 껄껄)

1. 관련 서적

좋은 지침서로는 O'Reilly handbook for sed and awk 이랍니다.
책 제목인지, 책 설명인지는 모르겠지만(한번도 본적이 없어서)
이정도면 원서를 다루는 서점에서는 찾을 수 있겠지요. (영어입니다. 껄껄)
"UNIX in a Nutshell" , "UNIX Power Tools" 같은 책도 추천한다네요.
(게을러서인지, 아직 한글 관련 문서를 발견하지를 못했습니다.
아시는 분 있으면 소개좀. 책 말고요 - 돈이 없어서 )

2. sed: 무엇에 쓰는 물건인고?

이글 제일 앞에서 설명한 바로 그런 작업을 보다 쉽게 해주는 물건이랍니다.
대부분의 유닉스 명령어가 그렇듯이 이것도 단지 표준 입력으로 입력받아,
원하는 처리를 해서, 표준 출력으로 그 결과를 보는 일 밖에
하지 않습니다.

최종목표는 현재 디렉토리와 그 하위 모든 디렉토리에 있는 .html 파일 안에
있는 모든 "Index"라는 문자열을 "색인"이라는 문자열로 바꾸는 것이지만,

sed가 하는 일은 딱 하나, 무조건 표준 입력에서 입력되는 내용 중에,
"Index"라는 문자열이 있으면, 그것을 "색인"이라는 문자열로 바꾸어서
표준 출력으로 보내는 일 밖에 하지 않습니다.

결국 나머지 일들은 쉘 스크립트에서 또 다른 명령어나,
쉘 스크립트 언어를 사용해야겠지요.

그 사용법은

sed 's/찾는문자열/바꿀문자열/g' 입력파일

이것이 가장 기본적인 사용법이랍니다.
이렇게 하면 앞에서 말했듯이 그 결과는 표준 출력으로 보내집니다.

또한 문자열을 지정할 때, 쉘 스크립트 작성때와 마찬가지로,
쉘에서 특별한 의미로 쓰이는 문자들은 '\' 문자를 앞세워서
사용합니다.

.*[]^$\

이 문자들이 sed, shell에서 특별한 의미로 쓰임으로
이 문자 자체를 의미하려면, '\' 문자를 먼저 사용해야겠지요.
예:

sed 's/[J.S. Bach {$ for music}]/[Bach, J.S {$ for music}]/' filename

이게 아니라,

sed 's/\[J\.S\. Bach {\$ for music}\]/[Bach, J.S {$ for music}]/' filename

이렇게.
여기서 하나 신기한 것은 "찾는 문자열"에서만 이런 것이 적용된다는 것입니다.
"바꿀 문자열"에서도 똑같이 지정하면, 그 지정한 그대로 출력되더군요.
(신기하나? 원래 당연한 것 아닌감? 표준 출력이니까.)

그럼 이것은 무엇일까요?

sed 's/\/usr\/bin/\/bin/g' filename

"/usr/bin" -> "/bin" 으로 바꾸는 것?
물론 오류가 있는 사용법은 아닙니다. 하지만, 경로명이 길어지면,
알아 보기가 힘들겠지요. 그래서, 경로명을 사용할 때는

sed 's#/usr/bin#/bin#g' filename

이렇게 한답니다.

또한 "Index"라는 문자열은 "색인"으로 바꾸고, "Contents"라는 문자열은
"차례"라는 내용으로 바꾸고 싶다면,
sed를 두번 사용하느냐? 이런 멍청한 짓(?) 하는 사람은 없겠지요.
이럴 때는

sed -e 's/Index/색인/g' -e 's/Contents/차례/g' 파일이름

이런 식으로 한답니다. '-e' 옵션은 "또 있다"는 뜻이랍니다.
이 옵션이 빠지면, 첫번째 경우만 처리하고 두번째 경우("차례"로 바꾸는 것)는
무시된다고 하네요.

3. 정규표현식(Regular Expression) 사용하기

모든 찾기가 그러하듯이 여기서도 여전히 정규식이 사용되는군요.

정규식 사용하는데 무리가 없는 사람은 별로 어려운 문제가 아니겠지요.
저는 잘 모르니까, 몇가지 예제를 들어보지요.

sed 's/^Thu /Thursday/' filename

이건 저도 아네요. 껄껄. '^' 기호는 그줄의 첫칸을 의미하지요.
즉, 줄 첫 칸에만 있는 "Thu" 문자열을 "Thursday"로 바꾸는 경우네요.
그런데, 여기서는 파일 전체를 대상으로 한다는 'g' 문자가 빠졌군요.
왜 빠져도 되는지는 모르겠지만, 아무튼 실행되더군요.

sed 's/ $//' filename

이건 반대로 줄 끝에 있는 공백 문자를 없애는 것입니다.
즉 " $" 문자열을 "" 문자열로. 텍스트 파일에 대한 기본적인 지신이 부족한
사람들에게는 "그게 뭐 어때서?" 하면서 의아해 하겠지만,
엄격히 따지면, " $" 문자열이란, 공백문자랑, 그 다음에 줄 바꿈 문자가
있는 것을 말합니다. 이것을 윗 명령으로 그 공백 문자를 없애는 경우입니다.

과연 이런 게 어디 쓰일까? 회의를 둘 수도 있겠지만,
의외로 필요할 때가 많습니다.
한 예를 들어 awk (요곤 기회 주어지면 다음에 하지요. sed 보다 복잡
하더군요.) 에서 마지막 필드 다음에 줄바꿈 문자가 있어야 되는데,
이렇지 못하고, 공백문자가 있어, 원하는 결과 값을 못 얻어 내는 경우가
있거든요. 이럴 때 유용하게 쓰입니다.

sed 's/^$/이건 빈 줄이다/' filename

줄 첫칸에 줄 바꿈 문자가 있다? 당연히 빈줄이지요. 껄껄.

sed 's/Apr .. ..:..:.. 1980/Apr 1980/g' filename

이런 식으로 많이 사용하지 않았나요?
vi 편집기나, grep 명령에서 말입니다.
'.'(점)은 임의한 한 문자를 뜻하지요.
윗 예제는 뭔고하면, "Apr 11 11:09:25 1980" 이런 식으로
(어디서 많이 보았지요?) 된 여러 경우들을 무조건 "Apr 1980"으로
통일하는 경우입니다.

sed 's/[Oo]pen[Ww]in/openwin/g' filename


sed 's/ [A-Z]\. / /g' filename

이것도 그럴 것 같은데. " D. " 문자열 같은게, " " 문자열로 바꾸는 것입니다.

sed 's/ [^A-DHM-Z]\. / /g' filename

이건 윗 예제와 반대지요.
즉, A,B,C,D,H,M,O,P,Q,R,S,T,U,V,W,Z,Y,Z 문자는 제외한 다른 단일 문자의
경우는 모두 공백문자로.

그 외에도 몇개 더 있는데, 뭐 그다지 중요한 것은 아니네요.
grep나, ls 명령에서 이미 잘 쓰고 있는 것들이니까,

* : 임의의 문자열.
[][^] 등.. 여러 표현식을 섞어서 사용하는 것.


4. sed 안에서도 자체적으로 저장을 한다는군요. (신기하기도해라)

이 말이 무신 말인고 하면,
앞에서 말한 sed의 개념으로 본다면, 단지, 표준 입력으로 입력받아,
표준 출력으로 단순히 변환해서 보내는 역활밖에 하지 않는데,
저장할 여력이 어디 있을까 하는데.....

이런 경우를 생각해 보지요.

"*남자*와 *여자*"라는 정규식에 맞는 문자열에서 공백문자를 두고
서로 바꾸어야할 경우. 지금까지의 개념으로 본다면,
이런 문제는 sed에서 불가능하지요.

먼저 발견되는 첫번째 환경을 저장하고,
다음 두번째 환경이 곧이어 발견되면 그것을 서로 바꾸면 되겠지요.

이렇게 하는 것이 "\(" "\)" (괄호)입니다.

sed 's/^\([A-Z][A-Za-z]*\), \([A-Z][A-Za-z]*\)/\2 \1/' filename

이것은 "문자열1, 문자열2" 이런 내용을 "문자열2 문자열1"로
바꾸는 것입니다. 어떻게 1, 2를 서로 바꾸느냐 하면, "바꿀문자열 지정부분에,
\2 \1 이런식으로 써주면 되지요.

영어 표현 중에, "Lastname, Firstname" 이런 것을 "Firstname Lastname"
이런 식으로 바꾸고자 할 때 유용하게 쓰인답니다.

필요에 따라 입력 파일의 특정 범위 내에서만 문자열 바꾸기를 해야할
경우가 생기는데, 이때는 s 앞에다 그 범위를 지정합니다.

sed '1,20s/foobar/fubar/g' filename

이것은 첫번째 줄부터 20번째 줄까지만 찾아서 바꾸는 것입니다.

sed '/^Aug/s/Mon /Monday /g' filename

이런 식도 가능하다네요. 즉, 줄 처음에 Aug (팔월인가?) 라는 문자열이
있는 그 줄의 Mon 이라는 문자열을 Monday 로 바꾸는 것입니다.

이 반대라면,

sed '/^Aug/!s/Mon /Monday /g' filename

이런 식으로.

또한 조건을 여러게 줄 수도 있습니다.

sed '/^Aug/,/^Oct/s/Mon /Monday /g' filename

어떻게 작동할 지 알겠지요?

지금까지 설명 예로든 것은 모두 바뀌는 부분을 포함해서, 입력된
모든 내용을 다시 표준 출력으로 보여줍니다.
필요에 따라 그 바뀌는 줄에 대해서만 출력해야 할 경우가 생기지요.

sed -n 's/fubar/foobar/gp' filename

이런 식으로 사용하는데, 이때 주의 할 것은 -n 옵션을 사용한다는 것과
끝부분에 g가 아니라, gp라는 것.


5. 파일로 저장된 sed 명령. sed 스크립트.

여러 sed 명령을 계속 사용해야 할 경우는 이 작업을 또 보다 편하게
할 수 없을까? 해서, 생겨난 것이 스크립트인데, 가령,

s/color/colour/g
s/flavor/flavour/g
s/theater/theatre/g

한 파일에 이렇게 입력하고, sample.sed 라는 이름으로 저장한 후,
이것을 사용하려면 다음과 같이 합니다.

sed -f sample.sed filename

그럼 쉘 스크립트에서 실행 프로그램을 지정하는 #! 기호를 사용하면,

#!/usr/bin/sed -f
# This file is named "sample2.sed"
s/color/colour/g
s/flavor/flavour/g
s/theater/theatre/g

이렇게 작성하고, sample2.sed 라는 이름으로 저장한 후,

chmod u+x sample2.sed

./sample2.sed filename

이렇게 바로 하나의 독자적인 스크립트로 사용할 수도 있겠지요.
Posted by Bees
TAG sed, 유닉스

독도 지도

분류없음 2008/08/10 00:25
사용자 삽입 이미지


























이미지를 클릭하면 큰 이미지를 볼 수 있습니다.
Posted by Bees
TAG 독도, 지도
Posted by Bees
TAG 직장인
바탕 화면 왼쪽 하단의 [시작] 단추 오른쪽에 "바탕 화면 보기" 등 몇몇 아이콘을 담아둔 "빠른 실행" 항목이 있다. 바탕 화면이 일종의 폴더인 것처럼 이 빠른 실행도 폴더이며 탐색기로 찾을 때 그 위치는 다음과 같다.

C:\Documents and Settings\[사용자 이름]\Application Data\Microsoft\Internet Explorer\Quick Launch\
Posted by Bees