카테고리 보관물: Programming

[Shell Script] 인라인 파이썬코드로 ini 파일 파싱

Shell Script에서 python 을 이용하여 ini 파일 파싱


의도

쉘 스크립트를 이용해 /etc/systemd/system/서비스명 파일을 분석하려고 하니 스크립트에서 ini 형태의 파일을 분석하는게 조금 노가다성이라 pythonConfigParser 를 이용하면 좋겠다라는 생각이 들어 사용하였습니다.

[/etc/systemd/system/web-monitor.service] 샘플

[Unit]
Description=CHIeru Webmonitoring system.

[Service]
ExecStart=/usr/bin/node $INSTALL_PATH/server/server.js
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=web-monitor
User=root
Environment=\"NODE_CONFIG_DIR=$INSTALL_PATH/config\"

[Install]
WantedBy=multi-user.target

위의 부분에서 제가 필요한 부분은 Service 섹션의 ExecStart 값중 INSTALL_PATH 경로를 가져오는 것입니다.

[Shell Script code]

pathFromService=$(python - <<EOF
import ConfigParser
import os
Config = ConfigParser.ConfigParser()
Config.read('/etc/systemd/system/web-monitor.service')
executeCommand = Config.get('Service', 'ExecStart')
executeFilePath = executeCommand.split(' ')[1]

installationPath = os.path.abspath(os.path.dirname(executeFilePath) +'/../')

print installationPath
EOF
)
    LEN=$(echo ${#pathFromService})
    echo $pathFromService

[AutoHotKey] 볼륨 제어 스크립트

키보드로 리얼포스(REALFORCE)를 사용하면서 불편함이 미디어를 제어할 수 있는 키가 없다는 점이 불편했습니다.

사무실에서 음악을 듣다가 주변 사람이 말을 걸면 음악을 멈춰야 되는데 매번 마우스로 클릭해서 음소거 기능을 켜자니 불편해서 찾아보다보니 AutoHotKey를 이용해서 볼륨제어가 가능하다는 것을 알게 되었습니다.

키보드 매핑 프로그램을 여러가지가 있지만 간단하게 제가 원하는 기능만 사용하면 되므로 매핑 프로그램을 사용할 필요는 없었습니다.

아래 스크립트를 컴파일 해서 시작 프로그램에 넣으면 끝납니다.

[Script]

;------------------------------------------------------------------------------
; File : volumn_controls.ahk
; Author: coozplz@gmail.com
; Date: 2016. 04. 06
; Desc: 볼륨 컨트롤 키가 없는 키보드에서 음량을 제어 하는 기능

;------------------------------------------------------------------------------
;                               단축키 목록
;------------------------------------------------------------------------------
;                   [Left or Right] Window + PageUp   : 음량 크게
;                   [Left or Right] Window + PageDown : 음량 작게
;                   [Left or Right] Window + End      : 음소거
;------------------------------------------------------------------------------

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Volume Up settings.
<#>PgUp::SoundSet +10
Return

; Volume Down setting.
<#>PgDn::SoundSet -10
Return

; Mute toggle settings.
<#>End::SoundSet, +1, , mute
Return

[C] Echo server/client

대학교 이후로 거의 접해지 못했던 C 를 다시 시작하고 있습니다.

다시 시작하는 이유는 회사에서 C 개발자가 필요하기 때문입니다. 처음이라 진입이 쉽지는 않겠지만 포기하지 않고 계속 하다 보면 언젠가는 되리라 생각합니다.

예제는 http://www.joinc.co.kr/w/Site/win_network_prog/doc/winsock_basic 의 코드를 참조하며 모르는 부분에 주석을 추가하였습니다.

지속적으로 이전에 java로 만들었던 채팅 서버, 메신저 서버 등을 만들어볼 생각입니다.

개발환경

  • IDE: Visual Studio 2012
  • OS: Windows 10

[echo_server.c]

/*
File: echo_server.c
Desc: 에코 서버.
        서버는 클라이언트의 접속 요청을 수락한 후 송신된 메시지를 출력 및 동일 메시지 송신 후 클라이언트의 연결을 종료하는 프로그램
Date: 2016. 04. 27
Author: coozplz@gmail.com
*/
#include &lt;winsock.h&gt;
#include &lt;stdio.h&gt;

// Winsock 라이브러리 로딩을 위한 코드
#pragma comment(lib, &quot;Ws2_32.lib&quot;);


#define MAX_PACKET_LEN 512
#define PORT 5552
#define BACK_LOG_SIZE 5

int main()
{
    WSADATA wsaData;
    int status;
    int socketLength;
    int readSize, writeSize;
    SOCKET endPointSocket, clientSocket;

    struct sockaddr_in SocketInfo, ClientSocketInfo;

    char buffer[MAX_PACKET_LEN];

    if (WSAStartup(MAKEWORD(2, 2), &amp;wsaData) != 0) {
        printf(&quot;WSAStartup error \n&quot;);
        return 0;
    }

    endPointSocket = socket(AF_INET, SOCK_STREAM, 0);

    if (endPointSocket == INVALID_SOCKET) {
        printf(&quot;endPointSocket is invalid \n&quot;);
        return 0;
    }

    printf(&quot;Server is running on port %d\n&quot;, PORT);

    // 구조체를 초기화한다.
    ZeroMemory(&amp;SocketInfo, sizeof(struct sockaddr_in));
    SocketInfo.sin_family = AF_INET;
    // htons(): Host 시스템에서 Network 로 short 형 데이터를 보낼 때 바이트 오더를 바꿔주는 함수
    SocketInfo.sin_port = htons(PORT); 

    // htonl(): long형 데이터의 바이트 오더를 바꿔주는 함수.
    // INADDR_ANY 는 OS에 설정되어 있는 아이피 어느것이나 바인딩 한다는 의미
    SocketInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 

    status = bind(endPointSocket, (struct sockaddr*)&amp;SocketInfo, sizeof(struct sockaddr_in));

    if (status == SOCKET_ERROR) {
        printf(&quot;failed to bind socket \n&quot;);
        return 0;
    }

    //
    // backlog 인자는 아직 미결인 연결들에 대한 큐의 늘어날 수 있는 최대 길이를 정의한다.
    // 큐에 도착한 연결 요청들이 꽉 찬다면 클라이언트는 ECONNREFUSED를 가리키는 에러를 받거나 만일 하위 프로토콜이 재전송을 지원한다면, 요청은 재시도가 성공되도록 하기 위해 무시된다.
    //
    status = listen(endPointSocket, BACK_LOG_SIZE);

    if (status == SOCKET_ERROR) {
        printf(&quot;failed to listen socket \n&quot;);
        return 0;
    }

    while (TRUE) {
        // 클라이언트 구조체 초기화
        ZeroMemory(&amp;ClientSocketInfo, sizeof(struct sockaddr_in));
        socketLength = sizeof(struct sockaddr_in);

        clientSocket = accept(endPointSocket, (struct sockaddr *) &amp;ClientSocketInfo, &amp;socketLength);
        if (clientSocket == INVALID_SOCKET) {
            printf(&quot;client socket is invalid\n&quot;);
            closesocket(clientSocket);
            continue;
        }

        // inet_ntoa() : 네트워크 바이트 순서의 32비트 값을 Dotted-Decimal notation 의 주소값으로 변환
        // 예 0x6601a8c0: 102.1.168.192
        printf(&quot;[Accepted] %s:%d\n&quot;, inet_ntoa(ClientSocketInfo.sin_addr), (int)ntohs(ClientSocketInfo.sin_port));
        ZeroMemory(&amp;buffer, sizeof(buffer));
        readSize = recv(clientSocket, (void *)buffer, MAX_PACKET_LEN, 0);

        if (readSize &gt; 0) {
            printf(&quot;Message from client &gt; %s\n&quot;, buffer);
            writeSize = send(clientSocket, buffer, readSize, 0);
        }
        else {
            printf(&quot;Error on reading\n&quot;);
        }
        closesocket(clientSocket);
        printf(&quot;[Closed] %s:%d\n&quot;, inet_ntoa(ClientSocketInfo.sin_addr), (int)ntohs(ClientSocketInfo.sin_port));
    }
    closesocket(endPointSocket);
    WSACleanup();
    return 0;
}

[echo_client.c]

/*
File: echo_client.c
Desc: 에코 클라이언트.
      서버에 접속 요청을 한 후 사용자가 입력한 메시지를 서버에 송신 후 응답 메시지를 출력한 후 소켓 연결이 종료되었는지 판단하고 소켓 연결을 종료한다.
Date: 2016. 04. 27
Author: coozplz@gmail.com
*/

#include &lt;stdio.h&gt;
#include &lt;WinSock2.h&gt;

// Winsock 라이브러리 로딩을 위한 코드
#pragma comment(lib, &quot;Ws2_32.lib&quot;);


#define PORT_NUM 5552
#define MAX_LEN 1024

int main(int argc, char **argv)
{
    SOCKET socketFd;
    WSADATA wsaData;
    struct sockaddr_in addr;

    char buffer[MAX_LEN];
    char receiveBuffer[MAX_LEN];

    int status = 0;
    int readSize = 0;
    status = WSAStartup(MAKEWORD(2, 2), &amp;wsaData);

    if (status != NO_ERROR) {
        printf(&quot;WSAStart has error\n&quot;);
        return 1;
    }

    socketFd = socket(AF_INET, SOCK_STREAM, 0);

    if (socketFd == INVALID_SOCKET) {
        printf(&quot;socketFd is invalid\n&quot;);
        return 1;
    }
    ZeroMemory(&amp;addr, sizeof(struct sockaddr_in));

    addr.sin_family = AF_INET;
    //
    // inet_addr() : Dotted-decimal 타입을 네트워크 32바이트 순서로 변경
    //
    addr.sin_addr.S_un.S_addr = inet_addr(&quot;192.168.10.52&quot;);
    addr.sin_port = htons(PORT_NUM);

    status = connect(socketFd, (struct sockaddr_in *)&amp;addr, sizeof(addr));

    if (status == SOCKET_ERROR) {
        printf(&quot;connection failed...\n&quot;);
        return 1;
    }

    while (TRUE) {
        printf(&quot;Connection is established...\n&quot;);
        printf(&quot;&gt; &quot;);
        fgets(buffer, MAX_LEN - 1, stdin);
        if (strncmp(buffer, &quot;quit\n&quot;, 5) == 0) {
            break;
        }

        printf(&quot;SEND: %s&quot;, buffer);
        send(socketFd, (void *)buffer, strlen(buffer), 0);
        ZeroMemory(&amp;receiveBuffer, sizeof(receiveBuffer));
        readSize = recv(socketFd, (void *)receiveBuffer, MAX_LEN, 0);
        printf(&quot;READ = %s\n&quot;, receiveBuffer);
        //
        // 소켓연결이 종료되었는지 판단하기 위해 다시 recv() 함수를 호출한다.
        //
        ZeroMemory(&amp;receiveBuffer, sizeof(receiveBuffer));
        readSize = recv(socketFd, (void *)receiveBuffer, MAX_LEN, 0);
        if (readSize &lt;= 0) {
            printf(&quot;socket is disconnected by server!!\n&quot;);
            break;
        }
    }
    closesocket(socketFd);
    WSACleanup();

    printf(&quot;Press any key to exit program.&quot;);
    getchar();
    return 0;
}
이 글은 C 카테고리에 분류되었고 , 태그가 있으며 님에 의해 에 작성되었습니다.

[Shell Script] JSON parsing using Nodejs

Shell Script에서 Nodejs를 이용하여 JSON 값 가져오기


의도

쉘 스크립트를 이용해 프로그램 설치시 방화벽에 자동으로 포트를 추가하려고 하니 설정 정보는 JSON 파일로 되어 있어 쉘 스크립트만으로 파싱하기는 어려움이 있습니다.

다행히 프로그램이 nodejs 기반으로 돌아가는 어플리케이션이라 쉘 스크립트에서 nodejs 를 이용하여 파싱하고 값을 가져오는 처리를 하였습니다.

※ 다른 방법도 많이 있습니다. awkpython 을 이용하여 값을 가져오는 방법도 있으니 구글링해보시길 바랍니다.

입력, 실행 파일


[JSON file]

// default.json
{
    "http": {
        "port": 9080
    },
    "websocket": {
        "port": 9070
    },
    "peerjs": {
        "path": "/peerjs",
        "port": 9000,
    }
}

[Shell script file]

// test.sh

# http 포트 정보 가져오기 
HTTP_PORT=$(node -pe 'JSON.parse(process.argv[1]).http.port' "$(cat default.json)")

# peerjs 포트 정보 가져오기
PEERJS_PORT=$(node -pe 'JSON.parse(process.argv[1]).peerjs.port' "$(cat default.json)")

# websocket 포트 정보 가져오기
WEBSOCKET_PORT=$(node -pe 'JSON.parse(process.argv[1]).websocket.port' "$(cat default.json)")

echo "HTTP port is $HTTP_PORT"
echo "PEERJS port is $PEERJS_PORT"
echo "WEBSOCKET port is $WEBSOCKET_PORT"

# Output
# HTTP port is 9080
# PEERJS port is 9000
# WEBSOCKET port is 9070

실행


// 스크립트에 실행 권한을 추가 
> chmod u+x test.sh

// 스크립트 실행
> ./test.sh

[Script] bash root 권한 확인

Bash 스크립트 작성시 ROOT 여부 확인

아래와 같이 코드를 도입부에 추가하면 루트 권한이 있는 경우에만 실행 되도록 할 수 있습니다.

#!/bin/bash
ROOT_UID=0
E_NOTROOT=67

if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Script have to execute on ROOT mode"
exit $E_NOTROOT
fi

Cordova Pros & Cons

Cordova


최근에는 Feedly 를 이용하여 제가 주로 보는 글을 RSS 형태로 보고 있습니다. 매번 사이트에 들어가서 확인하기도 힘들고 해서 이용하는 굉장히 편리한 어플리케이션 입니다.

오늘 본 글 중에 Cordova의 정의, 동작원리, 장점, 단점등에 대한 내용중 장, 단점과 Phonegapcordova 에 대한 내용만 정리해보려고 합니다.

정리 내용중에는 제 경험도 일부 포함하였습니다.

원문: http://code.tutsplus.com/tutorials/an-introduction-to-cordova-basics–cms-25146

장단점

새로운 프로젝트에 cordova 또는 Phonegap을 도입하려고 한다면 아무래도 집중적으로 살펴야 하는 부분이 단점에 대한 부분인거 같습니다.

신경쓰지 않으면 나중에 아주 힘든 상황이 발생될 수 있습니다.

장점

1. 쉽게 배울 수 있다.

cordova는 HTML페이지만 잘 만든다면 바로 사용할 수 있습니다.

2. 네이티브 API 접근 가능

카메라, 연락처, 위치정보, 미디어등 기기에서 제공하는 항목에 대해 접근이 가능합니다.

3. 공짜

제가 생각하는 가장 중요한 이유입니다.

4. 오픈소스

5. 다양한 커뮤니티 및 많은 사용자

cordova에 관련된 이슈에 대해 문제 해결을 하기 위해 검색하면 많은 결과가 나옵니다. 비슷한 이슈사항을 가진 사람이 많으면 버그도 빠르게 수정될 수 있습니다.

6. 다양한 플랫폼 지원

안드로이드, iOS, Windows에 모두 지원되는 어플리케이션을 단일 코드로 작성할 수 있습니다.

단점

단점에 대한 경험을 제가 아는대로 공유해보겠습니다.

1. 문서 미흡

2. 네이티브 소스보다 느리다.

당연한 내용이지만 cordova 로 어플리케이션을 개발하면서 네이티브 어플리케이션과 동일한 성능을 나타낸다는 것은 어불성설입니다.

cordova는 하나의 소스로 다양한 플랫폼을 지원하는 편의성이 있지만 거기에 따른 비용을 무시할 수는 없습니다. 이것은 다른 하이브리드 어플리케이션도 비슷하다고 생각합니다.

3. 프레임워크

iOS 네이티브 어플리케이션의 경우 UITableView 형태의 구현이 정말 쉽습니다. 그렇지만 이와 같은 형태를 Phonegap으로 구현하기 위해서는 네이티브보다 훨씬 어려운 방법이 동원되어야 합니다.

또한 네이티브에서 사용되는 페이지 전환 애니메이션 효과를 나타내기 위해서도 많은 코드및 꼼수가 포함되어야 합니다.

cordova가 HTML 페이지를 Webview 에서 표시하는 형태이기 때문에 어플리케이션 사용시 네이티브 어플리케이션과 유사하게 만들어야 한다면 많이 어렵습니다.

4. 플러그인 버그

iOS 9 버전이 발표되며 고객사의 요구사항에 어플리케이션 대상에 iOS 9이 포함되었습니다. 요청에 대해 대응을하고자 빌드를 하였지만 iOS8에서는 정상동작을 하지만 iOS 9에서 잘못 표시되는 항목이 발생하였습니다.

원인은 포함된 플러그인의 버그 였습니다. 저희가 선택할 수 있는 방법은 플러그인이 업데이트 되기를 기다리는 방법과 플러그인을 사용하지 않고 빌드된 파일을 변경하는 방법이었습니다.

결론은 빌드된 파일을 변경하였습니다. 3rd 파티 플러그인의 경우 개발자가 빠르게 대응해준다면 고마운 일이지만 그렇지 않다면 언제 개선될지 모르기 때문입니다.

5. 모든 플랫폼에 동일하지 않다

폰갭으로 빌드한 결과물을 실제 단말에 올려보기 전에는 화면 표시 및 다른 부분이 어떻게 동작할지 예상할 수 없습니다. iOS에서 동작이 잘되니까 Android에서도 잘되겠지라는 생각은 금물입니다.

폰갭(Phonegap)과 Cordova

Phonegap API를 참조하다 보면 링크가 cordova 페이지로 넘어가는 경우가 많습니다. 간단하게 생각하면 cordova를 한번 감싼게 Phonegap이라고 생각됩니다.

두개를 로컬에서 빌드한다면 명령어만 다르고 나머지는 대동소이합니다.

[Nodejs] CentOS 설치

1. Download Node binary

https://nodejs.org/en/download/ 링크로 이동하여 바이너리 파일을 다운로드 합니다.

* 아래 링크는 설치 일시 및 노드 버전에 따라 달라질 수 있습니다.

$ wget https://nodejs.org/dist/v4.2.4/node-v4.2.4-linux-x64.tar.gz

2. 압축 해제 및 압축 해제 파일 이동

2.1 다운로드 파일 압축 해제

$ tar xfz node-v4.2.4-linux-x64.tar.gz

2.2 압축 해제 파일 이동

$ mv node-v4.2.4-linux-x64 /usr/local/node

3. 환경 변수 설정하기

자신의 환경 변수 파일을 수정합니다. (.profile or .bashrc)

[~/.profile]

export NODE_HOME=/usr/local/node
export PATH=$PATH:$NODE_HOME/bin

4. 설치 결과 확인

[coozplz@localhost ~]$ node
&gt; console.log('helloworld')
helloworld
undefined

[Java] Lambda(Stream) 는 항상 좋을까?

[원글] http://www.javacodegeeks.com/2015/12/3-reasons-shouldnt-replace-loops-stream-foreach.html

Java 1.8이 출시된 후 많은 블로그 및 홈페이지에서 Lambda 를 소개하는 글들이 많이 올라와 있습니다. 그렇지만 대부분의 글에 Lambda의 장점들에만 치중하는 내용이 대부분인데 오늘 RSS 피드에 괜찮은 내용이 있어 요약해 봅니다.

1. 성능

Lambda(Stream) 와 For-loop 방식의 처리에는 성능의 차이가 발생된다.

ArrayList, for-loop : 6.55 ms
ArrayList, seq. stream: 8.33 ms
int-array, for-loop : 0.36 ms
int-array, seq. stream: 5.35 ms

위의 성능의 차이는 어찌 보면 큰 차이는 아닌것 같지만 대량의 데이터를 처리해야 하는 로직에 포함된 Stream API라면 많은 성능 차이를 일으킬 수 있습니다.

2. 가독성

저도 간단하게 Stream API를 이용하여 Filter및 Collector를 이용하면서 소스 코드가 확연히 줄어든 경험이 있지만 가독성은 Stream API를 사용하기 전보다 떨어지는 것을 느꼈습니다.

단순 리스트에서 동일한 값을 뽑아내는 형태의 것은 문제가 없다고 생각하지만 Filter를 이용해서 값을 추출하고 추출한 값을 다시 가공하고 연산하여 데이터를 취합하는 형태를 구현 한다면 훨씬 복잡하고 이해하기 힘든 코드가 될 것이라는 생각입니다.

또한 다수의 사용자가 동일한 코드를 작업하는 환경이라면 모든 사용자가 익숙하지 않다면 Stream API 사용을 자제하는 것이 좋다고 생각됩니다.

3. 유지보수

대부분의 코드는 단발성이 아닌 수정이 빈번하게 발생되는 경우가 있습니다. Stream API를 사용하는 경우 StackTrace에 불필요한 내용이 출력되어 오류 분석에 어려움이 있을 수 있습니다.

[For-loop]

Exception in thread &amp;quot;main&amp;quot; java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:13)

[Lambda]

Exception in thread &amp;quot;main&amp;quot; java.lang.ArithmeticException: / by zero
    at Test.lambda$1(Test.java:18)
    at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
    at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557)
    at Test.lambda$0(Test.java:17)
    at java.util.Arrays$ArrayList.forEach(Arrays.java:3880)
    at Test.main(Test.java:16)

이상입니다.

[InnoSetup] MsgBox 일본어 깨짐

문제점

InnoSetup에서 경고창을 띄우기위해 code 섹션에 MsgBox 함수를 호출하는 경우가 있는데 iss 파일에서는 정상적으로 일본어를 입력하였으나 실제 출력되는 내용은 깨진 글자가 출력되는 현상

해결방안

아래 소스와 같이 언어 설정을 하고 커스텀메시지를 추가한다. 추가한 커스텀 메시지를 MsgBox에서 호출하도록 처리하면 일본어 글자가 정상적으로 출력된다.

[Languages]
Name: jp; MessagesFile: "compiler:Default.isl"

[CustomMessage]
jp.CheckError='権限がありません。'

[Code]
procedure InitializeWizard;
begin
MsgBox(ExpandConstant('{cm:CheckError}'), mbInformation, MB_OK);
end;

[Python] 크리스마스트리

제작 의도

어제 다음 카페 게시글을 보다 보니 각 학과별 크리스마스트리를 그리는 방법이라는 글이 올라와 있어 Python을 이용하여 크리스마스 트리를 제작해봤습니다.

모두 즐거운 성탄절 되세요..!!

소스 코드

ROW = 9


def printTree(maxCountOfSpaceNStart):
    for i in range(1, maxCountOfSpaceNStart):
        print '%*s%*s' % (ROW-i, ' ', 0, '*' * (i * 2 -1))

if __name__ == '__main__':
    print '=' * 20
    print '%2s%s' % (' ', 'Merry Christmas!!!')
    print '=' * 20
    trees = [5, 7, 9]
    for i in trees:
       printTree(i)

실행 결과

====================
  Merry Christmas!!!
====================
        *
       ***
      *****
     *******
        *
       ***
      *****
     *******
    *********
   ***********
        *
       ***
      *****
     *******
    *********
   ***********
  *************
 ***************