카테고리 보관물: Programming

[Tool] atom editor

 atom editor 사용기

원래 저는 새로운 프로그램을 사용하는 것을 굉장히 즐겨합니다. 새로운 프로그램을 사용하게 되면 새로운 단축키, 친숙하지 않은 UI 그리고 새로운 기능들에 대해 적응 하는 것을 굉장히 즐겨하는 편입니다.

친해지는데 어려움이 있지만 친해지고 나면 왠지 기분이 좋은 느낌이 들어서 입니다.

제가 사용해본 텍스트 에디터는 아래와 같이 여러개가 있습니다. 윈도우에서 기본으로 제공하는 노트패드는 제외했습니다.

  1. notepad++
  2. Editplus
  3. UltraEdit
  4. EmEditor
  5. atom
  6. vim
  7. sublime3

대략 3달정도 사용한 것 같은데 현재는 사용하지 않고 있습니다. 사용하지 않는 이유는 단점 부분에서 말씀드리도록 하겠습니다.

장점

여러가지 좋은 기능이 있겠지만 제가 생각하는 장점입니다.

테마

다른 에디터에 비해 기본 테마가 아주 마음에 들었습니다. 솔직히 테마는 기능에 영향을 주는 것은 아니지만 툴에서 굉장히 중요한 부분을 차지한 다고 생각합니다. 프로그래밍 도구를 설치하면 저는 가장 먼저 하는 일이 폰트와 테마를 변경하는 것입니다.

어두운 계열의 테마가 저는 마음에 들었는데 문법 강조나 다른 색상들이 아주 마음에 들었습니다. 너무 많은 색상을 사용하지 않은 것 같으면서 많이 사용한..

플러그인

대부분의 에디터들이 플러그인을 제공합니다. 그렇지만 회사에서 제공하는 플러그인만 있는 것이 아닌 사용자가 필요한 플러그인을 오픈소스로 만들어서 제공하기 때문에 제가 필요한 플러그인 정보는 거의 있었습니다.

또한 플러그인 매니저를 통해 설치 과정도 쉽고 사용하기도 쉬운 편입니다.

크로스 플랫폼

개발 환경을 OSX, Windows를 사용하기 때문에 OS별로 에디터를 변경해서 사용하는 것은 제 생각에는 별로 좋지 않다고 생각합니다. atom 에디터의 경우 크로스 플랫폼을 지원하기 때문에 다른 OS에 가더라도 단축키가 헷갈리거나 기능이 헷갈리지 않습니다.

오픈소스

마지막으로 atom 에디터는 github 에 소스가 공개되어 있습니다. 참조
저도 개발을 하는 입장이지만 크로스 플랫폼 에디터의 소스를 볼 수 있다는 것은 큰 이점입니다.

아직 보지는 못했습니다.

단점

제가 생각하는 단점입니다. 성격이 별로 불평을 하지 않는 편이라 많이는 없습니다.

제가 현재 사용하지 않는 이유는 기동시간 때문입니다.

텍스트 편집기라는 것은 복잡한 파일에 대한 수정 보다는 간단한 파일을 수정하는 경우가 많은데 기동시간이 오래 걸린다는 것은 수정하는데 시간이 오래 걸린다는 의미이기 때문에 멋진 테마를 포기하고 구동이 빠른 EmEditor를 사용하고 있습니다.

기동시간

이것은 크로스 플랫폼을 지원해서인지 몰라도 구동 시간이 생각보다 오래 걸립니다. 제가 atom 에디터 이후 notepad++EmEditor를 사용했는데 둘 간에 비교를 해봐도 많은 차이가 납니다.

그리고 전체적인 동작이 조금 느린 것 같다는 느낌이 듭니다.

큰 파일

로그 파일 100MB 이상을 여는데 시간이 오래 걸립니다. 만약 더 큰 파일을 여는 경우 atom 에디터가 죽는 현상이 발생됩니다. notepad++EmEditor의 경우는 그러한 증상이 별로 발생하지 않았습니다.

이상으로 atom에디터에 대한 제 생각을 마치겠습니다.

[Tool] ILMerge

DLLEXE를 하나의 실행 파일로 만들기

C#을 이용해서 네트워크 테스트용 프로그램을 만들었는데 log4net.dllini-parser.dll 을 참조해서 실행 파일 하나로는 안되는 상황..

테스트 과정을 예상하니

  1. 테스트 프로그램을 USB에서 PC로 복사한다.
  2. 압축된 프로그램을 해제한다.
  3. 해제된 프로그램을 실행한다.

너무 불편할 것 같다는 생각이 들었습니다.

만약 실행 파일만 있다면 2번 과정이 생략되니 훨씬 편할 것 같았습니다.

http://stackoverflow.com/questions/10137937/merge-dll-into-exe

stackoverflow에서는 커맨드라인을 활용한 방법을 소개했는데 만들어보니 정상적으로 실행은 됐는데 실행 파일이 생성되지 않는 증상이 나타났습니다.

결국 ILMergeGUI 버전을 받아 쉽게 처리했습니다.

https://ilmergegui.codeplex.com/

[Git] 문서파일 비교

git 레포지토리에는 MS-OFFICE 문서 파일이 포함되는 경우가 많이 있습니다.

만약 본인 또는 다른 사람이 문서 파일을 변경한 경우 문서의 어떤 부분이 변경 되었는지 확인 할 수 있다면 보다 효율적으로 업무를 볼 수 있습니다.

해당 내용은 Pro Git 이라는 책에도 어느정도 설명이 된 부분이지만 실제로 테스트를 해가며 적용한 내용을 공유하고자 합니다.

DOC[X] 비교

문서 파일을 비교하는 것은 pandocApache Tika 를 사용하는 방법이 있습니다. 물론 이외에 여러가지 방법이 있습니다.

 

pandoc 적용방법

1. Git Config 파일 수정

아래의 내용을 `.gitconfig` 파일에 추가합니다. `USER_HOME` 디렉토리는 `C:/Users/로그인계정` 입니다.

[USER_HOME/.gitconfig]

[diff "pandoc"]
textconv=pandoc --to=markdown
prompt = false

[alias]
wdiff = diff --word-diff=color --unified=1

2. Git Repository 디렉토리에 .gitattribute 파일 추가

Git 레포지토리로 이동하여 .gitattribute 파일을 생성한 후 아래의 내용을 넣습니다.

*.docx diff=pandoc

3. 문서 변경 부분 확인

저는 임의로 `test.docx` 라는 문서를 만들고 테스트를 했습니다.
`test.docx` 라는 파일에는 애국가가 적혀 있습니다.

[test.docx]

동해물과 백수산이 마르고 닳도록 하느님이 보우하사 우리나라만세.

이후 무궁화 삼천리 화려강산 대한 사람 대한으로 길이 보전하세 라는 후렴부를 추가했습니다.
비교된 결과를 확인해보겠습니다.

$ git diff
diff --git a/test.docx b/test.docx
index 44c02f2..27dc279 100644
--- a/test.docx
+++ b/test.docx
@@ -1 +1,3 @@
동해물과 백수산이 마르고 닳도록 하느님이 보우하사 우리나라만세.
+^M
+무궁화 삼천리 화려강산 대한 사람 대한으로 우리나라 만세.^M

불필요한 글자가 출력되기는 하지만 수정된 내용이 표시되었습니다.
무궁화 삼천리 화려강산 대한 사람 대한으로 길이 보전하세 소절에서 화려강산 이란 단어를 삭제하였습니다.

$ git diff
diff --git a/test.docx b/test.docx
index 27dc279..71bbf31 100644
--- a/test.docx
+++ b/test.docx
@@ -1,3 +1,3 @@
동해물과 백수산이 마르고 닳도록 하느님이 보우하사 우리나라만세.

-무궁화 삼천리 화려강산 대한 사람 대한으로 길이 보전하세.
+무궁화 삼천리 대한 사람 대한으로 길이 보전하세.^M

변경된 라인이 모두 출력됩니다.


Tika 적용방법

Apache Tika 의 경우 PPTX 포맷과 DOCX 포맷을 모두 지원한다는 장점이 있습니다.

1. Tika 다운로드

https://tika.apache.org/download.html 에서 tika-app 항목을 다운로드 합니다. 제가 테스트 하는 시점에서 tika 버전은 1.12 입니다.

2. 환경 변수 설정

다운로드한 tika-app-1.12.jar 파일을 환경 변수에 추가하거나 저장 위치를 확인합니다.

3. 배치 파일 생성

배치 파일은 .gitconfig 에서 호출하기 위함과 파라미터를 받기 위함입니다. tika 를 실행할 때 사용하는 옵션에는 여러종류가 있습니다. (링크참조)

[USER_HOME/tika.bat]

java -jar [TIKA 저장경로] -t --encoding=UTF-8 %1

4. `.gitconfig` 파일 수정

위에서 `pandoc` 적용 방법에서 수정한 `.gitconfig` 파일을 다시 수정합니다.
아래 부분에서 `openxml` 부분이 추가 되었습니다. `textconv` 속성에 위에서 작성한 `tika.bat` 파일의 경로를 지정합니다.

[USER_HOME/.gitconfig]

[diff "pandoc"]
textconv=pandoc --to=markdown
prompt = false
[alias]
wdiff = diff --word-diff=color --unified=1
[diff "openxml"]
textconv=C:/Users/coozplz/tika.bat

5. Git Repository 디렉토리에 .gitattribute 파일 수정

위에서 설정된 .gitattribute 파일을 아래와 같이 수정합니다.

*.docx diff=openxml
*.pptx diff=openxml

6. 문서 변경 부분 확인

위에서 수정한 내용을 커밋한 상태가 아니기 때문에 동일한 내용이 다시 출력됩니다.

$ git diff
diff --git a/.gitattributes b/.gitattributes
index 51cead2..ef6a520 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,2 @@
-*.docx diff=pandoc
+*.docx diff=openxml
*.pptx diff=openxml
warning: LF will be replaced by CRLF in .gitattributes.
The file will have its original line endings in your working directory.
diff --git a/test.docx b/test.docx
index 27dc279..71bbf31 100644
--- a/test.docx
+++ b/test.docx
@@ -1,4 +1,4 @@

-D:\temp>java -jar "C:\\Users\\coozplz\\tika.jar" -t --encoding=UTF-8 C:/Users/coozplz/AppData/Local/Temp/IjVuPa_test.docx
+D:\temp>java -jar "C:\\Users\\coozplz\\tika.jar" -t --encoding=UTF-8 test.docx ^M
동해물과 백수산이 마르고 닳도록 하느님이 보우하사 우리나라만세.
-무궁화 삼천리 화려강산 대한 사람 대한으로 길이보전하세.
+무궁화 삼천리 대한 사람 대한으로 길이보전하세

실행이 약간 느리기는 하나 문제없이 출력되는 것을 확인할 수 있습니다.

PPTX 변경 내용 확인

test.docx 문서와 마찬가지로 애국가 1절을 후렴부 없이 입력하고 커밋한 후 후렴부를 추가하였습니다.

$ git diff
diff --git a/test.pptx b/test.pptx
index 64fc17b..09ecd25 100644
--- a/test.pptx
+++ b/test.pptx
@@ -1,9 +1,10 @@

-D:\temp>java -jar "c:\\Users\\coozplz\\tika.jar" -t --encoding=UTF-8 C:/Users/coozplz/AppData/Local/Temp/F4N97a_test.pptx
+D:\temp>java -jar "c:\\Users\\coozplz\\tika.jar" -t --encoding=UTF-8 test.pptx ^M
애국가
1절
동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세.
+무궁화 삼천리 화려강산 대한사람 대한으로 길이 보전하세.

PPT문서를 텍스트 형태로 비교하는 내용을 확인 할 수 있습니다.

위에서 언급은 하지 않았지만 xlsx 문서 및 이미지 파일 비교도 가능합니다.

해당 내용은 나중에 올리도록 하겠습니다.

이 글은 Tools 카테고리에 분류되었고 태그가 있으며 님에 의해 에 작성되었습니다.

[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