koodev

'전체 글'에 해당되는 글 75건

  1. Regular expression in sed
  2. How to terminate a background process
  3. macOS에 emacs ggtags 설치 및 설정

Regular expression in sed

Programming

sed(1) 에서 사용되는 정규표현식에 대해서 알아보기 위해 Overview of Regular Expression Syntax 의 내용을 옮겨본다.

sed 를 잘 쓰기 위해서는 정규표현식(regexp)을 잘 알아야 한다. 정규표현식이란 주어진 문자열(subject string)에서 왼쪽에서 오른쪽으로 봐가면서 매칭되는 패턴을 의미한다. 정규표현식에서 대부분의 문자들(character)은 일반문자(ordinary)이다. 즉 이 문자들이 패턴 자체이고 주어진 문자열에서 해당 문자들이 나올 경우 매칭되게 된다. 예를 들어 아래와 같은 패턴은,

The quick brown fox

그 자체가 패턴이 된다. 하지만 정규표현식의 강력한 기능은 패턴을 작성함에 있어서 대치(alternatives)와 반복(repetitions)이 가능하다는 점이다. 정규표현식에서 대치와 반복은 특수문자를 써서 표현할 수 있다. 이렇게 특수문자로 쓰인 패턴은 그 자체가 패턴이 되는 것이 아니라 뭔가 특별한 용도를 위해 다르게 처리된다. 그럼 아래에 sed 에서 쓰이는 정규표현식 문법에 대해 정리해 보겠다.

Pattern Meaning
char 그 자체가 패턴이 되는 일반문자를 나타냄.
* * 앞에 나오는(preceding) 정규표현식이 0번 이상 매칭되는 패턴을 의미한다. '앞에 나오는 정규표현식'에는 ①일반문자, ②백슬래시(\)로 시작하는 특수문자, ③점(.), ④(아래에서 설명할)정규표현식 그룹, 그리고 ⑤대괄호로 묶여진 표현식 등이 될 수 있다. GNU 확장규칙(extension) 에서는 정규표현식이 * 뒤에서 나올(postfixed)수도 있다. 예를 들어, a**a* 랑 같다. POSIX 1003.1-2001에 의하면 * 은 어떤 정규표현식이나 서브익스프레션의 시작부분에 등장할 경우 별(*) 그 자신을 의미한다고 되어있다. 하지만 많은 non-GNU 유틸들은 이를 지원하지 않으며, 같은 상황에서 포터블 스크립트들은 \* 을 대신 사용한다.
\+ * 과 동일하지만 매칭되는 패턴의 개수가 1개 이상이다. GNU extension.
\? * 과 동일하지만 매칭되는 패턴의 개수가 0 또는 1개 이다. GNU extension.
\{i\} * 과 동일하지만 매칭되는 패턴의 개수는 정확히 i 번이다. 여기서 i는 10진수 정수지만 0~255 사이의 값을 사용하는것이 안전하다.
\{i,j\} i에서 j 개가 매칭된다.
\{i,\} i 번 이상 매칭된다.
\(regexp\) 내부 regexp를 그룹지을 때 사용한다. 그룹이 사용되는 예를 살펴보면 아래와 같다.
  • postfix operator로서 사용된다. 예를 들어, \(abcd\)* 은 'abcd' 문자열이 0번 이상 나오는 패턴이다. 단, 이는 POSIX 1003.1-2001 에 의한 GNU extenstion 이므로 non-GNU 유틸에서는 지원하지 않는다. 따라서 호환성을 고려한다면 안 쓰는게...
  • (뒤에서 설명할)Back reference 에 사용된다.
. 개행을 포함한 모든 캐릭터와 매칭된다.
^ 어떤 패턴에서 시작 부분의 널문자와 매칭된다. 이게 무슨 말이냐면, 꺾쇄문자(^) 다음에 오는 패턴은 패턴의 시작부분이라는 얘기다.

대부분의 sed 스크립트에서 패턴은 새 행이 시작될 때마다 초기화된다. 따라서 ^#include 의 경우 해당 행은 '#include' 라는 문자열로 시작되어야 하는 것이다. 만일 '#include' 앞에 공백이 있는 행일 경우에는 패턴매칭이 실패한다. 또한 이는 패턴 스패이스에서 원본 컨텐츠가 수정되지 않은 경우, 예를 들어 s 커맨드를 사용할 경우에만 유효하다.

^는 정규표현식이나 서브익스프레션에서 맨 앞에 나오는 특수문자로서도 쓰일 수 있다. POSIX에서 ^를 일반문자로 취급하는것을 허용하기는 하지만 포터블 스크립트에서는 서브익스프레션의 시작부분에 ^를 사용하는 것을 피하는 것이 좋을 것이다.
$ ^ 와 비슷하지만 맨 끝부분 패턴을 나타낸다. $ 도 역시 정규표현식이나 서브익스프레션에서 맨 끝에있는 특수문자를 가리키는데 쓰일 수 있다.
[list]
[^list]
list 내부의 단일 문자와 매칭된다. 예를 들어, [aeiou] 은 모든 모음 문자(vowels)와 매칭된다. listchar1-char2와 같은 표현식 (char1char2사이에 있는 모든 단일 캐릭터) 으로도 사용할 수 있다.

여기서 맨 앞에 ^이 나올 경우 list의 의미를 반전시킨다. 즉, list안에 있는 문자들을 제외한 단일 문자가 된다. 이스케이핑(escape) 관련하여 특수문자인 ]list 안에 포함시키기 위해서는 대괄호 닫음(])을 맨 처음에 넣으면 되고(^가 필요할 경우 ^를 먼저 넣는다), 특수문자 -list 안에 넣기 위해서는 대시(-)를 맨 처음이나 맨 나중에 넣는다. 특수문자 ^ 의 경우에는 첫 문자 다음에 넣도록 한다.

특수문자 $, *, ., [, \ 들은 list 안에서 특수문자(특별한의미)로 동작하지 않는다. 예를 들어 [\*] 이것은 '\' 이나 '*' 문자가 매칭된다. 왜냐하면 \list 안에서 특수문자(특별한의미)로 동작하지 않기 때문이다. 그렇지만 [.ch.], [=a=], [:space:] 들은 list 안에서 그별한 의미를 지니며 각각은 ch 이중문자(collating symbol; ch 체코어?), a 와 동등한 정렬순서를 갖는 문자집합(equivalence class), 공백을 나타내는 문자클래스(character class)를 의미한다. 즉, [list 안에서 ., =, : 등과 함께 쓰였을 경우 특별한 의미를 갖게된다. 또한 POSIXLY_CORRECT 모드가 아닐 경우 \n 이나 \t 과 같은 특수문자들도 list 안에서 특별한 의미를 갖는다. Escape 참고.
regexp1\|regexp2 regexp1 이나 regexp2 를 매칭한다(OR). 소괄호()를 사용하면 여러개를 이어서 사용할 수도 있는 것 같다. 매칭 과정은 왼쪽부터 시작해서 오른쪽으로 가면서 정규표현식들을 검사하고, 제일 처음 매칭된 정규표현식을 사용하게 된다. GNU extension 이다.
\digit 정규표현식 안에서 digit 번째의 소괄호 \(...\) 로 둘러싸인 서브익스프레션과 매칭된다. 이것을 back reference 라고 한다. 서브익스프레션은 암묵적으로 왼쪽에서 오른쪽으로 보면서 \( 이것이 나온 개수에 대하여 넘버링이 되어있다.
\n 개행 문자와 매칭된다.
\char char 와 매칭한다. 여기서 char$, *, ., [, \, ^ 이들 중에 하나이다. 이스케이핑(escape) 용도라는 말임. 참고로 C언어에서의 백슬래시 조합 특수문자 중에 \n 이나 \\ 이런것은 사용할 수 있다. 하지만 \t 는 대부분의 sed 구현에서 빠져있다. 즉, 탭 문자가 아니라 t로 매칭을 시도하게 된다.

정규표현식의 매칭방식은 좌에서 우로 나아가며 매칭하고, 같은 위치에서 두 개 이상의 매칭이 발견되었을 경우에는 긴 쪽을 택한다. 그래서 greedy(탐욕스러운) 하다라고도 한다.

아래는 정규표현식 예제들이다.

'abcdef'
쓰여진 그대로 'abcdef' 와 매칭됨.
'a*b'
0개 이상의 'a'와 그 다음에 'b'가 나오는 경우와 매칭된다. 예를 들면 'b'나 'aaaaab'.
'a\?b'
\? 는 0개 또는 1개 와 매칭되는 것이다. 따라서 'b' 또는 'ab' 와 매칭된다.
a\+b\+
\+ 는 1개 이상과 매칭되는 것이다. 따라서 1개 이상의 'a'와 이어서 1개 이상의 'b'가 오는 경우이다. 가장 짧게 매칭되는 경우가 'ab' 이고 'aaaab', 'abbbbb', 'aaaaaabbbbbb' 이렇게도 가능하다.
'.*/
'.\+'
둘 다 모든 캐릭터 문자열과 매칭되는 경우이다. 단, 위의 케이스는 널 스트링을 포함한 모든 문자열과 매칭되지만, 아래것은 최소한 하나의 문자는 들어있는 문자열과 매칭된다.
'^main.*(.*)'
'main'으로 시작하고, 소괄호로 둘러쌓인 문자열이 이어지는 경우이다. 'n'과 '('과 ')' 이 위치가 반드시 딱 붙어있어야 하는것은 아니다.
'^#'
'#'으로 시작하는 문자열과 매칭된다.
\\$
백슬래시(\) 하나로 끝나는 문자열과 매칭된다. 백슬래시를 두 개 썼지만 하나는 escaping 용도로 쓴 것이다.
'\$'
달러 기호 하나와 매칭된다. 여기에 쓰인 백슬래시도 escaping 용도로 쓰였다.
'[a-zA-Z0-9]'
환경변수 로케일이 C locale 인 경우, 모든 ASCII 문자 혹은 숫자와 매칭된다.
'[^ tab]\+
여기서 tab 은 탭 문자이다. 이 예제는 공백이나 탭 문자를 제외한 한 글자 이상의 캐릭터와 일치한다. 즉, 한 단어(word)를 의미한다.
'^\(.*\)\n\1$'
\(regexp\) 은 그룹을 이루고 back reference 로도 쓰인다. 이 예제는 두 개의 동일한 문자열 사이에 개행문자가 하나 들어간 꼴이다.
'.\{9\}A$'
9개의 문자에 이어서 A가 나오는 패턴이다.
'^.\{15\}A'
16개의 문자로 시작하고, 그 16개 중에 마지막 문자가 A인 경우이다.

'Programming' 카테고리의 다른 글

Bash에서 문자열 검색 조건식 만들기  (0) 2018.07.22
Truncate PWD in prompt (MacOS)  (0) 2018.04.29
How to terminate a background process  (0) 2018.04.24
macOS에 emacs ggtags 설치 및 설정  (0) 2017.10.17
Xcode에 assimp 올리기  (0) 2017.06.06

How to terminate a background process

Programming

가끔 실행중인 프로세스를 종료시키고 싶을 때 Ctrl + c 가 먹지 않는 경우가 있다. 이럴때 나는 Ctrl + z 로 실행중인 프로세스를 백그라운드로 돌려놓고, PID를 알아낸 다음에 SIGKILL 시그널(9번)을 보내는 식으로 처리하곤 했다.

그런데 이것을 좀 쉽게 하는 방법이 있었다.

  • 모든 백그라운드 프로세스 끝내버리기: kill -9 $(jobs -p)
  • 백그라운드 프로세스 하나만 끝내버리기:
    우선 jobs 명령어로 모든 백그라운드 프로세스의 목록을 가져온 다음에,
    kill %1 하면 첫 번째 프로세스를 끝낼 수 있고,
    kill %2 하면 두 번째 프로세스를 끝낼 수 있다.

참고: https://unix.stackexchange.com/questions/104821/how-to-terminate-a-background-process

'Programming' 카테고리의 다른 글

Truncate PWD in prompt (MacOS)  (0) 2018.04.29
Regular expression in sed  (0) 2018.04.25
macOS에 emacs ggtags 설치 및 설정  (0) 2017.10.17
Xcode에 assimp 올리기  (0) 2017.06.06
OpenGL로 원 그리기  (1) 2017.05.27

macOS에 emacs ggtags 설치 및 설정

Programming

macOS에 emacs ggtags 설치 및 설정하는 과정을 정리한다. 성공한 환경은 아래와 같다.

  • macOS Version: macOS Sierra 10.12.6 (16G29)
  • emacs Version: GNU Emacs 25.1.1 (x86_64-apple-darwin13.4.0, NS appkit-1265.21 Version 10.9.5 (Build 13F1911)) of 2016-09-21

1. 설치

1.1 Homebrew로 ruby, ctags 설치

brew install --upgrade ruby
brew install --HEAD ctags

1.2 Homebrew로 GNU Global 설치

brew install global --with-exuberant-ctags

1.3 pygments 플러그인 설치

sudo pip install pygments
sudo pip3 install pygments

pygments는 Syntax Highlighter이다. ctags가 레퍼런스 탐색 기능을 제공하지 않기 때문에 Global에서 pygments 플러그인을 사용하도록 설정해 주어야 한다.

2. 설정

2.1 pygments 설정

시스템 환경 변수(.bashrc 등)에 아래와 같이 설정해준다.

export GTAGSCONF=~/.globalrc
export GTAGSLABEL=pygments

즉, Emacs에는 아래와 같이 해주면 된다.

(setenv "GTAGSCONF" (concat (expand-file-name "~") "./globalrc"))
(setenv "GTAGSLABEL" "pygments")

만일 ~/.globalrc 파일이 없다면, /usr/local/share/gtags/gtags.conf 파일을 복사하여 ~/.globalrc 로 만든다. 그리고 :ctagscom= 을 검색하여 아래와 같이 바꿔준다(2개 정도 나옴).

exuberant-ctags|plugin-example|setting to use Exuberant Ctags plug-in parser:\
  :tc=common:\
  :ctagscom=/usr/local/opt/ctags/bin/ctags:\

...

pygments-parser|Pygments plug-in parser:\
  :ctagscom=/usr/local/opt/ctags/bin/ctags:\

2.2 Emacs 설정

(and
 (require 'ggtags nil t)
 (message "ggtags initializing...")
 (autoload 'ggtags-mode "ggtags"
   "Minor mode for browsing source code using GLOBAL" t))

(eval-after-load 'ggtags
  '(progn
     (add-hook 'c-mode-common-hook
               (lambda ()
                 (when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'objc-mode)
                   (ggtags-mode 1))))
     (add-hook 'python-mode-hook (lambda () (ggtags-mode 1)))

     ;; Set GTAGS variables
     (setenv "GTAGSCONF" (concat (expand-file-name "~") "/.globalrc"))
     (setenv "GTAGSLABEL" "pygments")

     (define-key ggtags-mode-map (kbd "C-c C-f") 'ggtags-find-file)
     (define-key ggtags-mode-map (kbd "C-c g") 'ggtags-grep)
     ))

(provide 'koodev-ggtags)

3. 실행

프로젝트 폴더로 가서 소스파일을 하나 열고 M-x ggtags-find-tags-dwim 을 실행하면 루트 폴더의 위치를 묻는데, 프로젝트 루트를 지정해주면 잠시 후 G* 파일들이 생성된다.

단축키 등의 자세한 정보는 다음 링크를 참고한다: https://github.com/leoliu/ggtags

4. 기타

ImportError: No module named pygments 이런 에러가 뜨는 경우, 우선은 pygments 플러그인을 잘 설치했나 확인해보고, 실행 환경에서 python이 어느 경로로 잡혀있는지 확인해본다. 내 경우에는 시스템에 python이 두 개가 설치되어 있었는데, 터미널을 열 경우와 Emacs나 다른 유틸(GNU Global)을 실행하는 시점에서 python 경로가 달라 위와 같은 에러가 떴다. 추가로 설치된 python을 삭제하고 pygments 등을 재설치해 주었더니 문제가 해결되었다.

References

'Programming' 카테고리의 다른 글

Regular expression in sed  (0) 2018.04.25
How to terminate a background process  (0) 2018.04.24
Xcode에 assimp 올리기  (0) 2017.06.06
OpenGL로 원 그리기  (1) 2017.05.27
Swift3 - result unused warning 없애기  (0) 2017.05.23