기본 콘텐츠로 건너뛰기

9월, 2007의 게시물 표시

Windows에서 F1이 도움말로 작동하지 않도록 하기

주변인 분류

내 주변인은 딱 두 종류인 듯. 일반인 과 덕후 . 참고로 일반인은 자신이 일반인이란 자각 자체가 없으나, 덕후들은 자기가 일반인이라고 우김. 원본 위치: http://purewell.egloos.com/3411286

부하가 걸리는 함수 찾기 - callgrind

valgrind에 여러 도구 가운데 callgrind 라는 녀석이 있다. 함수 호출 회수와 걸린 시간 등을 긁어주는 프로파일러이다. 사용법은 무지 간단하다. $ valgrind --tool=callgrind [프로그램] [프로그램 인자] 이렇게 하면 callgrind.out.[PID]로 중간 파일이 뛰쳐 나온다. 이걸 callgrind_annotate 같은 텍스트 툴로 보면 대략 눈 많이 아프더라. KDE용 프로그램 가운데 KCachegrind 라는 녀석이 있다. valgrind-callgrind 같은 패키지 깔면 같이 깔리는 기특한 녀석이다. KCachegrind를 실행하고 위에서 나온 callgrind.out 파일을 열면 함수별 부하가 눈에 보기 편하게 나온다. (내부적으로 dot을 이용하는 모양) 덧글: 프로그램은 -pg 옵션은 필요하지 않으며, -g 옵션은 해줘야 쓸만한 정보가 뛰쳐나온다. 원본 위치: http://purewell.egloos.com/3410603

애완동물은 안고 통과하자!

한가위에 부산에 가야하는데 KTX보다 돈 쪼꼼만 더 주면 더 빠르고 더 편안하게 갈 수 있는 비행기 를 이용하기로 했다. 탑승 수속을 밟으면서 X-ray로 짐을 검사하는 곳에 로빈을 담아둔 가방을 통과시키려고 하자 검사하는 분이 뭐냐고 묻는다. 고양이라고 했더니, 짐을 검사하는 X-ray로 통과하면 안 된다고 한다. 이때 소심한 샘이와 잼이는 고양이 데리고 비행기 타면 안 된다는 소리로 들었다. 분명히 5Kg 이내 애완동물은 들고 타도 괜찮다고 들었는데 말이야... 잠시 멀뚱거리는 동안 검사하는 분이 고양이를 안고 금속 탐지기를 지나가라고 했다. 생명체는 짐을 검사하는 X-ray를 통과하면 안 된다는군. 무사히 수속을 마치고 부산까지 별 탈 없이 잘 날아갔다. 원본 위치: http://purewell.egloos.com/3407971

map::find(const string&) const 피하는 방법 없을까?

STL에 map과 string을 엮어서 자주 사용하는 편인데, 일반적인 규모에서는 흡족할만한 성능을 보여주기에 별 불만이 없다. 하지만 대용량처리(초당 1,000,000건 정도?)를 하다보면 실망스럽기 서울역에 그지 없다. 다음 소스를 보면 암묵적 형변환 에 의해 얼마나 그지 같이 느려지는지 알 수 있다. testFunc(size_t cnt) { map<string,void*> tmpcont; const char* key_1("Hello, world! What are you doing?"); const string key_2(key_1); // 100만개 아이템을 우겨넣는다. (생략) // C-style string key t1 = getTimestamp(); for (size_t i(0); i<cnt; i++) { tmpcont.find(key_1); } t2 = getTimestamp(); cerr << t2-t1 << endl; // STL string key t1 = getTimestamp(); for (size_t i(0); i<cnt; i++) { tmpcont.find(key_2); } t2 = getTimestamp(); cerr << t2-t1 << endl; } 결과는 약 5배 차이가 난다. -_-; 5배 차이라고 해봤자, 1,000,000건에 0.1초 차이이지만, 대용량 처리에서 저런게 누적하기 시작하면 대략 난감하다. map에서 반드시 key_type과 동일한 타입을 인자로 갖는 비교 함수를 쓰지 않는다면 어떻게 해보겠지만, 정말이지 초난감할 뿐이다. 어떻게 하지...? 원본 위치: http://purewell.egloos.com/3400058

임시변수와 스택

C/C++을 하다보면 자기도 모르는 사이에 임시변수를 쓰곤하는데, 대부분 암묵적 형변환에 의해서이다. 이때 발생하는 임시변수는 어디에 만들어지는 것일까? 보통 함수 내 자동 변수들은 프로세스 스택에 만들어지는 것으로 알고 있다. 정말 그런지 알아봐야겠다. #include <iostream> #include <string> using namespace std; volatile bool gTest(true); const char gString[] = "Hello, world!"; template<typename _T> void _func(const _T& v) { cerr << "Temporary variable: " << (void*)&v << endl; cerr << "Temporary buffer: " << (void*)(v.c_str()) << endl; } template<typename _T> void callStack(void) { _T local1; cerr << "Type ID: " << typeid(local1).name() << endl; cerr << "Local1 variable: " << (void*)&local1 << endl; cerr << "Local1 buffer: " << (void*)(local1.c_str()) << endl; if ( gTest ) { _T local2; cerr << "Local2 variable: " << (void*)&local2 &

floating pointer numbers class

상수 FP_NAN - 숫자가 아님. FP_INFINITE - 양 또는 음의 방향으로 무한대. FP_ZERO - 0. FP_SUBNORMAL - 표현하기에 너무 작은 값. FP_NORMAL - 그외 정상적인 실수. 테스트 함수 fpclassify(x) - 테스트해서 위 상수를 돌려줌. isfinite(x) - FP_NAN이 아니면서 FP_INFINITE가 아님. isnormal(x) - FP_NORMAL임. isnan(x) - FP_NAN임. isinf(x) - FP_INFINITE임. C99 표준. 원본 위치: http://purewell.egloos.com/3398406

TLS - Thread Local Storage

쓰레드를 돌리다보면 해당 쓰레드에서만 유효한 변수를 만들고 싶을 때가 있다. 그럴 때 어떻게 해야할까? 쓰레드 개수만큼 벡터를 잡고, 해당 쓰레드마다 벡터 인덱스를 넘겨주는 것도 나름 방법이지만, 이러한 경우를 위해 TLS라는 것이 존재한다. 축약처럼 쓰레드 안에서만 따로 스토리지를 할당한 것인데, 일반 프로세스의 스텍과 비슷하나 그 크기는 프로세스 것보다 당연히 작고 제약이 심한 편이다. 뭐 암튼 그런게 있다고 치자. * GCC 메뉴얼 보면 TLS가 아니라 TSD(Thread Storage Duration)이라고 표현하였는데 대충 같은 말이다. 이것을 위해 POSIX는 pthread_key_create, pthread_get/setspecific 등 함수를 마련해놨지만 눈만 팽글팽글 돌고, 소스만 지저분해져 보일 것 같다. 귀찮으면 C99, C++98 표준 __thread 키워드를 사용하자. MSDN에 보니 __thread가 없어 보인다. 이가 없으면 잇몸으로라도... #define __thread __declspec( thread ) 대충 이 정도면 될 듯하다. 자자 각설하고, __thread란 키워드는 TLS에 변수를 선언해주는 일을 한다. 위에 나열한 pthread_* 함수를 호출하는 것으로 컴파일러가 대신 해석해주는 것일 수도 있으나 이건 가정이므로 넘어가고. 사용에 주의해야할 점은 아래와 같다. (대충대충 표준하고 MSDN 보면서 정리한 것임) 글로벌 변수나 static 변수에만 사용 가능하다. - function 안에 local 변수가 static이 아니라면 뭐더게 TLS에 저장할까? 당연히 그럴 필요가 없기 때문에 저런 제약이 있는 것이다. 이는 class에서 멤버 변수에도 적용한 법칙이다. static으로 선언한 멤버 변수에만 저 키워드를 사용할 수 있다. SO(DLL)과 로컬 영역을 넘나들면 뻑난다. - ... 그러니까 쓰지마라. 왜? 타입에 대한 한정자로 사용이 불가능하다. - const처럼 쓰지 말라는 것이고, 무

POSIX's thread tips

쓰레드 자신에 대한 핸들을 알고 싶다면, pthread_self라는 전역 변수를 사용할 것. 두 쓰레드 핸들을 비교하고 싶다면 pthread_equal(핸들1,핸들2)을 사용한다. 둘이 같으면 0이 아닌 값이 나온다. 쓰레드 Concurrency를 확인/설정하고 싶으면 pthread_get/setconcurrency를 사용할 것. CPU점유를 다른 쓰레드에게 양보하고 싶으면 pthread_yeild가 있다. Mutex Lock을 부모 자식 프로세스 간에 공유하고 싶다면 속성에 pthread_mutexattr_get/setpshared을 이용하여 PTHREAD_PROCESS_SHARED을 세팅한다. 컨디션 변수에도 비슷한 것이 있다. 원본 위치: http://purewell.egloos.com/3398251

10년이면 강산이 변할까...

10년 전인가... 뉴질랜드로 이민 간 절친한 친구가 있었다. 한 1~2년 정도 편지로 왕래하다가 소식이 끊겼는데, 싸이월드 동창회에 이름이 있길래 혹시나 하고 미니홈피 갔더니 역시나더군. ㅋㅋ. 키도 많이 컸고 이마도 많이 벗겨지고 살도 많이 쪘지만 개구쟁이 얼굴은 그대로더라. 공부하기 싫어서 떠난 것 같았는데, 법대 준비 중이라고 하더군. 10년이면 강산도 변한다더니, 사람도 확 바뀔 수도 있구나! 근데 이 녀석, 미소년 메신저 쓴다. 잇힝~* 난 네이똥만 쓰는데. -_- 원본 위치: http://purewell.egloos.com/3398072

느린 GNU std::string

신이 내린 축복이라 생각했던 std::string. 삭막하던 C/C++에 string이란 타입을 선사해주신 SGI에게 감사하고 있었다. 가변길이 string. 생각만 해도 아힝~*이 절로 나온다. 그러나... 씨밤. 상당히 평범한 상황에서 그냥 char[]을 쓰는 것보다 느리다. 그도 그럴 것이, assign에서 Allocator를 돌리기 때문이다. 예를 보자. void testChar(const char* data) { char field[10][1024+1]; // data를 ' '로 파싱해서 field에 strncpy함. (귀찮아서 패스) } void testString(const char* data) { string field[10]; // data를 ' '로 파싱해서 field에 assign(ptr+pos, length)함. (귀찮아서 패스) } 뭐, 대충 이런 코드가 있다고 치자. 위 함수들을 상당히 큰 수만큼 돌렸다고 치자. 퍼포먼스는 얼마 정도 될까? 자료를 전부 공개할 수 없다는 점은 대충 이해하시라. (아니면 만들어서 돌려보시던가) 약 3.5배 정도 string이 느리다. 그도 그럴 것이 char는 (1024+1)*10을 미리 stack에 잡아놓고 call을 호출한다. 그러나 string은 string이라는 instance만 stack에 쌓여 있고, 실제 메모리는 data를 파싱하여 assign하는 동안 내부적으로 new(malloc)을 호출하여 heap에 메모리 덩어리를 할당받는다. 이게 위에서 stack 지랄하는 것보다 훨씬 느리다. testString에서 for문을 하나 더 넣어서 파싱하기 전에 field에 reserve(1024+1)을 하면 빨라질까? 아쉽게도 더 느려진다. 실험에서는 거의 2배가 넘게 느려졌다. 안습인데?! -_- 더욱 날 경악케 하는 것은 string[] 대신에 vector<string>에 push_back을 했을 경우는 st

SK컴즈, 엠파스 인수

SK 커뮤니케이션의 '엠파스' 인수로 얻는 이득은? ㅡ_-)a 대기업이라는 이미지. 안 좋긴 무지 안 좋은 것 같다. 그래서 그런지 SK컴즈가 엠파스 인수한 것을 곱게 보는 눈빛이 별로 없는 듯 하다. 나도 SK가 돈지랄하나보다...라고 생각했다. 과연 그럴까? 현재 네이트닷컴(http://www.nate.com)나 싸이월드(http://www.cyworld.com)을 가보면 검색창이 있다. 뭐든 검색해보자. 사이트는 그대로이지만, 엠파스 열린검색 로고 등을 함께 볼 수 있다. 이것이 의미하는 바는 무엇일까? SK컴즈에 가장 큰 자산인 싸이월드에는 엄청난 사용자와 인맥, 그리고 그들이 만들어낸 각종 컨텐츠가 쌓여 있다. 그러나 그들은 엄청난 컨텐츠에 걸맞는 검색엔진이 없었다. 라이코스 코리아를 인수했지만, 네이트닷컴이나 싸이월드에서 검색한 결과는 네이버에 비하면 실망스러웠다. SK컴즈의 엠파스 인수합병은 이러한 현실에 대한 적절한 해결책이었다. 많이 늦긴 했어도 비로소 사용자가 원하는 결과 - 싸이월드 컨텐츠 - 를 내뿜어주는 검색엔진을 갖게 된 것이다. 아직은 싸이월드와 네이트닷컴에 검색부분에만 붙이는데 그쳤지만, 엠파스가 가진게 단지 검색엔진만이 아니기에 어떤 키메라가 나올지 기대한다. 덧글: ㅡ_-)b 덕분에 루반장이랑 사유리 미니홈피도 아주 즐겁게 서핑하고 있다. 흐흐흐흐~* 덧글2: 그래도 대기업 돈지랄 싫어~* 원본 위치: http://purewell.egloos.com/3386946

부등교(不登校)

부등교(不登校). 일본에서 학교를 다니는 것을 거부한 학생 또는 그 행위를 말한다. 지금도 그 바람이 부는지 어찌는지 모르겠지만, 2000년에 기회가 닿아 부등교 아이 - 학생이 아니다! - 들을 만난 적이 있다. 그때 당시 내 고정관념과 달리 아이들은 밝고 쾌활했으며, 학교만 다니지 않을 뿐 스스로 공부하는 것은 다를 바 없었다. 그들이 학교를 거부한 것은 여러 이유가 있었지만 결국 청소년 인권이 주안점이었던 것으로 기억한다. 단순히 돈 내고 다니는 학교라는 '사업장'에서 청소년으로서 누릴 수 있는 사람다움이 없어서였다고 할까. 서론이 길었다. 그 바람이 지금 대한민국에도 서서히 부는 것 같다. 원본 위치: http://purewell.egloos.com/3384467

GNU의 std::string은 같은 문자열을 공유한다.

보통 std::map에서 key로 std::string을 많이 쓰는데, 쓸 때마다 부담스러웠다. 이유는 key는 std::map에서 node를 만들 때 instance를 새로 만들고 복제하기 때문이다. 그러나 GNU의 std::string은 동일한 문자열은 같은 메모리영역을 공유하도록 만들었다. 따라서 복제가 이뤄져도 실제로 데이터를 복제하는 것이 아니라 내부 레퍼런스 카운터만 올라간다. /usr/include/c++/x.x.x/bits/basic_string.[h|tcc] 파일을 까보면 _M_is_shared()라는 private method가 assign을 비롯하여 여기저기 쓰여 있는 걸로 보아 확실하다. 이를 나름 증명해보자면, 아래 소스를 컴파일해서 돌려보자. #include <iostream> #include <string> #include <map> using namespace std; map<string,void*> gMap; int main(int, char**) { string str1("Hello, world!"); string str2(str1); string str3; str3 = str1; string str4; str4.assign(str1); gMap.insert(map<string,void*>::value_type(str1, NULL)); cout << "str1: " << (void*)str1.c_str() << endl; cout << "str2: " << (void*)str2.c_str() << endl; cout << "str3: " << (void*)str3.c_str() << endl; cout << "str4:

POSIX thread's condition

이런 상황을 생각해보자. 쓰레드가 있고, 그것은 평상시에 자는 상태(CPU점유율 0%)이다. 그런데 문득 할 일이 생겨서 침 흘리며 자고 있는 쓰레드를 두들겨 깨우고 싶다. 어떻게 하면 좋을까? volatile bool gWakeUp(false); void* _thr(void*) {     while (!gWakeUp) usleep(1000*1000);     // something... } int main(int,char**) {     // ... init thread.     gWakeUp = true;     return 0; } 이러면 쓰것나? 뭔가 찜찜허다. gWakeUp이 true로 바뀌더라도 _thr는 최악의 경우 1초 뒤에 반응을 보일 것이다. 아힝~* 싫어~* 그래서 나온 녀석이 Condition이다. 술 먹기 전에 한 번 먹고, 먹은 다음 날 한 번 먹는다는 그것!...은 아니다. #include <cstdarg> #include <pthread.h> #include <iostream> using namespace std; pthread_cond_t cond; pthread_mutex_t mtx; pthread_attr_t attr; // Just for console. pthread_mutex_t console_lock; void display(const char* fmt, ...) {     pthread_mutex_lock(&console_lock);     va_list lst;     va_start(lst, fmt);     vfprintf(stderr, fmt, lst);     va_end(lst);     pthread_mutex_unlock(&console_lock); } void* thr(void* param) {     const size_t no((size_t)param);     display("no. %u: I'm born!\n", no);  

ET와 LT

epoll에서 ET(Edge Triggered)와 LT(Level Triggered)는 무슨 차이일까? ET는 어떠한게 변경되었을 경우만 발생하며, LT는 변경해서 해소할 될 때까지 계속 발생한다. man 페이지에 있는 예를 좀 더 손쉽게 설명하자면... 파이프에 EPOLLIN을 건다. 파이프에 2K를 쓴다. epoll_wait 파이프에서 1K를 읽어온다. epoll_wait LT일 경우, 아직 파이프에 1K의 읽을 꺼리가 있기 때문에 5번 epoll_wait에서 이벤트를 검출할수 있다. 반면 ET는 읽을 꺼리와 상관 없이 파이프 버퍼 상태가 변동된 시점에서 딱 한 번 이벤트가 발생하기 때문에 3번 epoll_wait에서만 검출되고, 5번 epoll_wait에서는 검출되지 않는다. 원본 위치: http://purewell.egloos.com/3375379

epoll은 공평한가?

epoll은 공평할까? $man epoll... o Starvation ( Edge Triggered ): If there is a large amount of I/O space, it is possible that by trying to drain it the other files will not get processed causing starvation. This is not specific to epoll. The solution is to maintain a ready list and mark the file descriptor as ready in its associated data structure, thereby allowing the application to remember which files need to be processed but still round robin amongst all the ready files. This also supports ignoring subsequent events you receive for fd's that are already ready.... Edge Triggered에서 기아상태. 특별히 epoll에 국한된 문제는 아니라고 하는군. ㅡ_-)a 기본값은 Level Triggered이지만 정리하는 차원에서. #include <sys/types.h> #include <sys/socket.h> #include <sys/epoll.h> #include <iostream> #include <vector> #include <errno.h> #include <pthread.h> #include <sys/time.h> #include <signal.h> using namespace std; static long long getTimestamp(void) {     static struct timeval tv;  

공유객체 속도

UNIX 공유객체(shared object) 만들기 테스트 환경을 만들기 전에 파일명을 소개하겠다. Makefile - 빌드를 위한 스크립트 plgn.cpp - plgn.so를 위한 소스. func2 함수가 포함되어 있다. sotest.cpp - 시간 측정을 위한 소스. func1 함수가 포함되어 있다. 일단 Makefile TARGET=sotest plgn.so CXXFLAGS=-g -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT LDFLAGS=-ldl all:$(TARGET) clean:     $(RM) $(TARGET) *.o sotest:sotest.cpp plgn.so:plgn.o     $(CXX) $(CXXFLAGS) -shared -lc -o $@ $< plgn.o:plgn.cpp     $(CXX) $(CXXFLAGS) -c -fPIC $< 뭐, 대충 흉내만 내놓고... 다음은 plgn.cpp extern "C" void func2(volatile int*); void func2(volatile int* v) {     ++(*v); } 역시나 흉내내기. extern "C"를 붙여 맹글링 회피 능력을 +3 했다. (뻘소리) 다음은 sotest.cpp #include <iostream> #include <dlfcn.h> #include <sys/time.h> using namespace std; static const size_t testcount(1000000UL); long long getTimestamp(void) {     static struct timeval tv;     gettimeofday(&tv, NULL);     return 1000000LL*tv.tv_sec+tv.tv_usec; } extern "C" void func1(volatile int*); typede

급상승 중!

아잉, 내 이름이 왜 올라가 있어~* 설마 스캔들? 뉴스보기 설마 이것 때문에? 원본 위치: http://purewell.egloos.com/3373571

C++ explicit

보이지 않는 위험, 암묵적 형변환. C로부터 계승해온 아주 멋지구리한 녀석이지. 뭐, 나름대로 편하긴 해도 벌레 잡을 때 그지 같단 말이지. 아래 코드를 보자. #include <iostream> using namespace std; // -DDO_EXP 를 컴파일 옵션에 넣으면 실험할 수 있다. #if !defined(DO_EXP) #   define EXPLICIT #else #   define EXPLICIT explicit #endif // 몇몇 정보를 찍는 함수 template<typename _T> static void _showme(const char* fn, void* ptr, const _T& val) {     cout << fn << '(' << ptr << "): " << val << endl; } // 몇몇 정보를 찍는 매크로 #define showme(h) _showme(__PRETTY_FUNCTION__, \     this, \     (h) ) // 내 클래스 class CMyClass { public:     // 생성자1 - a     EXPLICIT CMyClass()     {         showme(this);     }     // 생성자2 - b     EXPLICIT CMyClass(int h)     {         showme(h);     }     // 생성자3 - c     EXPLICIT CMyClass(const CMyClass& h)     {         showme(&h);     } #if 0     // 대입연산자1 - d     CMyClass& operator = (int h)     {         showme(h);         return *this;     } #endif     // 대입연산자2 - d     CMyClass&a

돈이 필요한 구글

네이버 닮아가는 구글? - 전자신문 : 전자신문 ㅡ_-)a 글 제목이 많은 이를 낚을 것 같은... 각설하고, 구글도 MS나 NHN처럼 회사이며 이익집단이다. 어마어마한 데이터센터와 어마어마한 인재를 먹여살리려면 그만한 튼튼한 수익원이 있어야한다. 아무리 생각해봐도 AdSense와 검색만 가지곤 구글밥통을 채워줄 수 없어보인다. 나름대로 좋은 이미지를 가지고 열린 생각으로 별별 방법을 다 써봤지만, 결국 그렇게 그렇게 흘러가나보다. 뭐, 한 때 구글 이미지에 찬양하기도 했고 - 지금은 별 다른 감흥이 없지만 - 저렇게라도 먹고 살기 위해 바둥거리는 것에 대해 별 달리 비난할만한게 없다. 롱런해라. 원본 위치: http://purewell.egloos.com/3371757

알집, 잘못한 건 무엇?

알집. 알집과 관련해서 별별 에피소드가 많구먼. 헐헐헐. 알집이 처음 나왔을 때, ZipNAll도 있고, 밤톨이도 있고 별별 압축 프로그램이 많았지만, 공짜라는 이유 하나로 경쟁자를 가볍게 누르고 우리나라 최고 (설치율만) 압축 프로그램을 달성하였다. 하지만, 그들이 크게 잘못한게 있다. alz란 파일 포멧을 공개 하지 않았거나 최소 alz 파일을 풀 수 있는 라이브러리 를 제공하지 않았다는거다. 회사에서 alz 파일 포멧을 공개할 의무도 라이브러리를 제공할 의무도 없다. 그러나 이런 지원정책 이 없기에 수 많은 사용자가 alz 파일을 알집 외에 다른 기존 프로그램에서 풀지 못하는 불편함을 낳게된 것이다. 다른 것 다 필요 없다. RAR나 ACE처럼 압축을 해체만 해주는 DLL 파일이라도(UNIX계열은 SO) 제공해주면 살짝 눈 감아줄께. 물론 해당 라이브러리는 관공서나 기타 언제 어디서든 쓸 수 있게 라이센스도 열어주고 말이야. 이미 알집이 우리나라 시장을 지배하고 있으니 alz에 대해 폐쇄정책을 고수하지 않아도 시장을 지킬 수 있지 않겠어? 괜스레 알집 써서 alz로 압축해서 지원서 냈는데 그 이유로 떨어진 사용자도 구제할 겸 말이야. ㅡ_-)/ 건승 있길. 뱀발: 우리회사에서 알집 못 깔게 한다. 알집 쓰려면 사야한다. alz가 특별히 압축률이 좋은 것도 아니고, 옛 날과 달리 저장용량 단가가 매우 싸졌기 때문에 압축률에 목숨 걸 필요도 없다. 단순히 zip 하나면 된다. (UNIX는 tar+gzip/bzip2) 원본 위치: http://purewell.egloos.com/3371247

이 블로그의 인기 게시물

Bash Array, Map 정리

Bash에서 Array, Map에 대한 정리. (매번 찾기 귀찮) 찾아보진 않았지만, Bash에서 Array든 Map이든 동일하게 Map(C++에서 Unordered Map)으로 동작하는 것 같다. 왜냐하면, Array의 Index가 연속하지 않아도 동작한다. 그저 Key가 0 이상의 정수인 Map이랑 비슷하게 동작한다. 예) 1, 2, 3, 9, 10 Array # 생성 declare -a empty_array declare -a ar=(haha hoho baba "long string haha hoho") # 접근 echo "ar[0]=${ar[0]}" echo "all as array=${ar[@]}" # 큰따옴표 안에서 각 원소를 따로따로 전달한다. echo "all as one=${ar[*]}" # 큰따옴표 안에서 각 원소를 문자열 하나로 합쳐 전달한다. echo "indexes=${!ar[@]}" echo "indexes=${!ar[*]}" echo "length=${#ar[@]}" echo "length=${#ar[*]}" echo "last=${ar[-1]}" echo "last=${ar[@]: -1}" # 콜론 뒤에 빈 칸이 꼭 필요하다. 옛 방식 # 현재 상황 declare -p ar #(출력) declare -a ar=([0]="haha" [1]="hoho" [2]="baba" [3]="long string haha hoho") ar[100]=hello # 인덱스를 건너 뛰어도 동작한다. declare -p ar #(출력) declare -a ar=([0]="haha" [1]="hoho" [2]="baba" [3]=&

설치한 패키지에서 RPM 추출하기

오래된 패키지를 관리할 저장소가 없어졌고, 기존 패키지로 다른 서버를 세팅해야할 일이 생겼다면 RPM의 리패키지 기능을 이용해보자. $ rpm -e --repackage [PACKAGE_NAME] 위와 같이 리패키지하면, /var/spool/repackage/ 에 생성한 RPM파일이 있다. :-)