1 Javascript로 CLI기반의 앱을 만들어보기
2 명령어 실행의 성공과 실패에 대한 이야기
3 매개변수에 대해서
4 앱을 좀더 그럴듯 하게 만들기

Javascript로 CLI기반의 앱을 만들어보기

CLI기반이란 글씨만 있는 Terminal 환경을 의미하고 여기서 사용할 수 있는 앱을 만들어보는 방법에 대해 이야기해보고자 합니다
node, npm, git, ls, rm 등등 리눅스명령어라고 부를수 있는 것들이 이에 해당하며 우리도 우리가 만든 앱으로 여기에 하나 더 보태보고자합니다
CLI기반이 되는 이러한 리눅스명령어와 같은 형태로 앱을 만들게되면 어떠한 특정 작업들을 자동화하거나 하는 등에 있어서 큰 편리함이 만들어집니다

활용의 예시를 잠시 상상해보자면 다음과 같은것을 만들 수 있습니다

[응용사례1]
명령어 이름 distributeapp
내 앱을 여러플랫폼에 일괄 배포하는 기능을 한다
사용법: distributeapp --appstore --playstore --steam --msstore -p ./myapp

[응용사례2]
명령어 이름 genicon
앱은 다양한 해상도의 아이콘이미지파일을 프로젝트내에 준비해둬야 한다
2048*2048 해상도의 png 파일을 하나 준비하면 이것을 알아서 프로젝트에 셋팅되도록 한다
사용법: genicon -f icon.png -p ./myapp

[응용사례3]
명령어 이름 dishwashing
싱크대에 놓여져 있는 그릇들이 설겆이가 되고 씻긴 그릇들은 모두 제자리에 놓여지도록 한다
작동 원리는 동생의 메신저로 "설겆이해라" 라는 메세지를 보내고 동생의 가상화폐지갑으로 지정된 액수만큼의 비트코인을 전송하도록 한다
메신저는 텔레그렘메신저를 사용하고 제공되는 API를 사용하고 비트코인은 송금기능을 제공하는 API를 제공하는 거래소를 선정해서 사용한다.
사용법: dishwashing -b 0.001 -m "설겆이해라"

따라해보기

앱의 코드를 작성할 폴더를 준비하고 들어갑니다
bWtkaXIgfi9teWNsaWFwcDsKY2Qgfi9teWNsaWFwcDs=
mkdir ~/mycliapp; cd ~/mycliapp;
(참고로 ~ 는 홈경로를 의미하며 제 경우 ~/ 는 /Users/kst/ 와 동일합니다)

npm init 커맨드를 실행해서 폴더 안에 package.json 파일을 만들어줍니다
bnBtIGluaXQ7CgpUaGlzIHV0aWxpdHkgd2lsbCB3YWxrIHlvdSB0aHJvdWdoIGNyZWF0aW5nIGEgcGFja2FnZS5qc29uIGZpbGUuCkl0IG9ubHkgY292ZXJzIHRoZSBtb3N0IGNvbW1vbiBpdGVtcywgYW5kIHRyaWVzIHRvIGd1ZXNzIHNlbnNpYmxlIGRlZmF1bHRzLgoKU2VlIGBucG0gaGVscCBpbml0YCBmb3IgZGVmaW5pdGl2ZSBkb2N1bWVudGF0aW9uIG9uIHRoZXNlIGZpZWxkcwphbmQgZXhhY3RseSB3aGF0IHRoZXkgZG8uCgpVc2UgYG5wbSBpbnN0YWxsIDxwa2c+YCBhZnRlcndhcmRzIHRvIGluc3RhbGwgYSBwYWNrYWdlIGFuZApzYXZlIGl0IGFzIGEgZGVwZW5kZW5jeSBpbiB0aGUgcGFja2FnZS5qc29uIGZpbGUuCgpQcmVzcyBeQyBhdCBhbnkgdGltZSB0byBxdWl0LgpwYWNrYWdlIG5hbWU6IChteWNsaWFwcCkgbWNhcHAKdmVyc2lvbjogKDEuMC4wKSAKZGVzY3JpcHRpb246IFRoaXMgaXMgbXkgZmlyc3QgQ0xJIGFwcAplbnRyeSBwb2ludDogKGluZGV4LmpzKSAKdGVzdCBjb21tYW5kOiAKZ2l0IHJlcG9zaXRvcnk6IAprZXl3b3JkczogCmF1dGhvcjogCmxpY2Vuc2U6IChJU0MpIApBYm91dCB0byB3cml0ZSB0byAvVXNlcnMva3N0L215Y2xpYXBwL3BhY2thZ2UuanNvbjoKCnsKICAibmFtZSI6ICJtY2FwcCIsCiAgInZlcnNpb24iOiAiMS4wLjAiLAogICJkZXNjcmlwdGlvbiI6ICJUaGlzIGlzIG15IGZpcnN0IENMSSBhcHAiLAogICJtYWluIjogImluZGV4LmpzIiwKICAic2NyaXB0cyI6IHsKICAgICJ0ZXN0IjogImVjaG8gXCJFcnJvcjogbm8gdGVzdCBzcGVjaWZpZWRcIiAmJiBleGl0IDEiCiAgfSwKICAiYXV0aG9yIjogIiIsCiAgImxpY2Vuc2UiOiAiSVNDIgp9CgoKSXMgdGhpcyBPSz8gKHllcykgeWVz
npm init; This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help init` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (mycliapp) mcapp version: (1.0.0) description: This is my first CLI app entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to /Users/kst/mycliapp/package.json: { "name": "mcapp", "version": "1.0.0", "description": "This is my first CLI app", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this OK? (yes) yes

이렇게 하면 package.json 파일이 만들어질 것입니다.
물음에 모두 아무것도 입력하지 않고 엔터를 치면 기본값으로 package.json 의 내용을 구성하게됩니다.
그 중에서도 name에 대해서는 아무것도 입력하지 않으면 폴더이름인 mycliapp를 따라가게 되는데 이번에는 특별히 mcapp이라고 조금 변형을 줘보았습니다.

이제 js 코드를 담을 파일을 만들고 코드를 입력합니다
현재 mycliapp 폴더에는 package.json 파일만 하나 있습니다
package.json 파일이 위치한 같은 폴더 안에 mycode.js 라는 이름으로 파일을 하나 만들고 내용에는 다음의 코드를 담습니다
코드 작성시 개행은 CRLF가 아닌 LF로 해야하는 점을 신경써주세요
다음의 코드를 수행하면 12와 34를 더한 값을 출력해줍니다

IyEvdXNyL2Jpbi9lbnYgbm9kZQpjb25zb2xlLmxvZygxMiszNCk=
#!/usr/bin/env node console.log(12+34)

자 일단 여기까지 12와 34를 더한 값을 출력해주는 앱을 완성했습니다
딱히 유용하지 않은 무의미한 앱입니다
그러나 어쨋든 이것을 우리의 앱이라고 부릅시다.
완성한 앱을 실행해봅시다


bm9kZSBteWNvZGUuanM=
node mycode.js 46 이라고 출력됩니다 pwd 라고 입력하면 내가 현재 위치한 폴더 경로를 알 수 있습니다 pwd 로 입력해서 나온 경로에 mycode.js 파일이 존재한다면 node mycode.js 로 실행이 가능합니다 다른말로 파일이 존재하지 않는다면 실행이 불가능하다는 이야기가 됩니다 참고로 pwd 로 입력해서 나온 경로에 mycode.js 파일이 존재하는지 확인하는 방법은 다음 커맨드를 입력해보면됩니다
bHMgYHB3ZGAvbXljb2RlLmpzO2VjaG8gJD8=
ls `pwd`/mycode.js;echo $?
파일이 존재하지 않는다면 1, 존재한다면 0이 뜰것입니다.

즉 mycode.js 를 실행하기 위해서는 mycode.js 파일이 존재하는 폴더경로로 들어와서 실행을 해야한다는 이야기가 됩니다.
Y2Qgfi9teWNsaWFwcDsKbm9kZSBteWNvZGUuanM7
cd ~/mycliapp; node mycode.js;
아니면 mycode.js 의 절대경로를 입력해줘도 됩니다
bm9kZSAvVXNlcnMva3N0L215Y2xpYXBwL215Y29kZS5qcw==
node /Users/kst/mycliapp/mycode.js
소스코드 상단에 #!/usr/bin/env node 라고 써준 부분이 있는데요, 이 라인을 맨위에 써주게되면 터미널에서 다음과 같이 입력해도 실행이 됩니다
L1VzZXJzL2tzdC9teWNsaWFwcC9teWNvZGUuanM=
/Users/kst/mycliapp/mycode.js
혹은 해당 mycode.js 파일이 위치한 폴더 안에서 다음과 같이 입력해도 실행을 시킬 수 있습니다
Li9teWNvZGUuanM=
./mycode.js
(만약 실행이 안된다면 실행권한이 주어지지 않아서일 이유가 큽니다)

이제 내가 위치한 폴더 경로와 상관없이 아무데서나 mycode.js 를 hello 라고 입력하면 실행되게 해봅시다.
package.json 을 열어서 "bin":{ "hello":"./mycode.js"  } 를 추가합니다.
추가한 모습은 다음과 같습니다.
ewogICJuYW1lIjogIm1jYXBwIiwKICAidmVyc2lvbiI6ICIxLjAuMCIsCiAgImRlc2NyaXB0aW9uIjogIlRoaXMgaXMgbXkgZmlyc3QgQ0xJIGFwcCIsCiAgIm1haW4iOiAiaW5kZXguanMiLAogICJzY3JpcHRzIjogewogICAgInRlc3QiOiAiZWNobyBcIkVycm9yOiBubyB0ZXN0IHNwZWNpZmllZFwiICYmIGV4aXQgMSIKICB9LAogICJhdXRob3IiOiAiIiwKICAibGljZW5zZSI6ICJJU0MiLAogICJiaW4iOnsgImhlbGxvIjoiLi9teWNvZGUuanMiICB9Cn0=
{ "name": "mcapp", "version": "1.0.0", "description": "This is my first CLI app", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "bin":{ "hello":"./mycode.js" } }
그런 후 package.json 파일이 위치한 폴더 안에서 npm install -g 을 입력해줍니다
이 커맨드의 의미는 우리가 작성한 앱을 컴퓨터에 설치한다는 의미입니다
그리고 우리의 앱의 이름은 mcapp 입니다

그런데 설치과정중 다음과 같은 메세지를 출력하면서 에러가 발생 할 수 있습니다
bnBtIEVSUiEgY29kZSBFQUNDRVMKbnBtIEVSUiEgc3lzY2FsbCBzeW1saW5rCm5wbSBFUlIhIHBhdGggLi4vLi4vLi4vLi4vVXNlcnMva3N0L215Y2xpYXBwCm5wbSBFUlIhIGRlc3QgL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL21jYXBwCm5wbSBFUlIhIGVycm5vIC0xMwpucG0gRVJSISBFcnJvcjogRUFDQ0VTOiBwZXJtaXNzaW9uIGRlbmllZCwgc3ltbGluayAnLi4vLi4vLi4vLi4vVXNlcnMva3N0L215Y2xpYXBwJyAtPiAnL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL21jYXBwJwpucG0gRVJSISAgW0Vycm9yOiBFQUNDRVM6IHBlcm1pc3Npb24gZGVuaWVkLCBzeW1saW5rICcuLi8uLi8uLi8uLi9Vc2Vycy9rc3QvbXljbGlhcHAnIC0+ICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvbWNhcHAnXSB7Cm5wbSBFUlIhICAgZXJybm86IC0xMywKbnBtIEVSUiEgICBjb2RlOiAnRUFDQ0VTJywKbnBtIEVSUiEgICBzeXNjYWxsOiAnc3ltbGluaycsCm5wbSBFUlIhICAgcGF0aDogJy4uLy4uLy4uLy4uL1VzZXJzL2tzdC9teWNsaWFwcCcsCm5wbSBFUlIhICAgZGVzdDogJy91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9tY2FwcCcKbnBtIEVSUiEgfQpucG0gRVJSISAKbnBtIEVSUiEgVGhlIG9wZXJhdGlvbiB3YXMgcmVqZWN0ZWQgYnkgeW91ciBvcGVyYXRpbmcgc3lzdGVtLgpucG0gRVJSISBJdCBpcyBsaWtlbHkgeW91IGRvIG5vdCBoYXZlIHRoZSBwZXJtaXNzaW9ucyB0byBhY2Nlc3MgdGhpcyBmaWxlIGFzIHRoZSBjdXJyZW50IHVzZXIKbnBtIEVSUiEgCm5wbSBFUlIhIElmIHlvdSBiZWxpZXZlIHRoaXMgbWlnaHQgYmUgYSBwZXJtaXNzaW9ucyBpc3N1ZSwgcGxlYXNlIGRvdWJsZS1jaGVjayB0aGUKbnBtIEVSUiEgcGVybWlzc2lvbnMgb2YgdGhlIGZpbGUgYW5kIGl0cyBjb250YWluaW5nIGRpcmVjdG9yaWVzLCBvciB0cnkgcnVubmluZwpucG0gRVJSISB0aGUgY29tbWFuZCBhZ2FpbiBhcyByb290L0FkbWluaXN0cmF0b3IuCgpucG0gRVJSISBBIGNvbXBsZXRlIGxvZyBvZiB0aGlzIHJ1biBjYW4gYmUgZm91bmQgaW46Cm5wbSBFUlIhICAgICAvVXNlcnMva3N0Ly5ucG0vX2xvZ3MvMjAyMi0wNC0wOVQyMV8xOV8zNV82NDJaLWRlYnVnLmxvZw==
npm ERR! code EACCES npm ERR! syscall symlink npm ERR! path ../../../../Users/kst/mycliapp npm ERR! dest /usr/local/lib/node_modules/mcapp npm ERR! errno -13 npm ERR! Error: EACCES: permission denied, symlink '../../../../Users/kst/mycliapp' -> '/usr/local/lib/node_modules/mcapp' npm ERR! [Error: EACCES: permission denied, symlink '../../../../Users/kst/mycliapp' -> '/usr/local/lib/node_modules/mcapp'] { npm ERR! errno: -13, npm ERR! code: 'EACCES', npm ERR! syscall: 'symlink', npm ERR! path: '../../../../Users/kst/mycliapp', npm ERR! dest: '/usr/local/lib/node_modules/mcapp' npm ERR! } npm ERR! npm ERR! The operation was rejected by your operating system. npm ERR! It is likely you do not have the permissions to access this file as the current user npm ERR! npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and its containing directories, or try running npm ERR! the command again as root/Administrator. npm ERR! A complete log of this run can be found in: npm ERR! /Users/kst/.npm/_logs/2022-04-09T21_19_35_642Z-debug.log
설치 과정중 특별한 권한이 있어야 접근 가능한 폴더에 접근하고자하는데 권한이 안되서 실패했다는 내용입니다.
npm install -g 명령어 앞에 sudo 를 붙여서 실행하면 관리자 권한으로 설치명령을 수행하게 됩니다
c3VkbyBucG0gaW5zdGFsbCAtZwoKYWRkZWQgMSBwYWNrYWdlLCBhbmQgYXVkaXRlZCAzIHBhY2thZ2VzIGluIDUyOG1zCgpmb3VuZCAwIHZ1bG5lcmFiaWxpdGllcw==
sudo npm install -g added 1 package, and audited 3 packages in 528ms found 0 vulnerabilities
이런 메세지를 출력하며 정상적으로 설치가 되었습니다

npm list -g 명령어를 입력해서 설치된 앱의 목록을 볼 수 있습니다
L3Vzci9sb2NhbC9saWIK4pSc4pSA4pSAIGNvcmVwYWNrQDAuMTAuMArilJzilIDilIAgbWNhcHBAMS4wLjAgLT4gLi8uLi8uLi8uLi9Vc2Vycy9rc3QvbXljbGlhcHAK4pSU4pSA4pSAIG5wbUA4LjEuMA==
/usr/local/lib ├── corepack@0.10.0 ├── mcapp@1.0.0 -> ./../../../Users/kst/mycliapp └── npm@8.1.0
이제 아무 위치에서나 hello 를 입력하면 46이 출력되게 되었습니다
성공
아래의 내용은 자세히 더 알고싶다면 참고해주세요

커맨드 자동완성에 대해

명령어는 모두 입력하지 않고 중간까지 입력하고 tab 을 누르면 자동완성되게 됩니다
예를들어 ifconfig 라고 한다면 ifcon 까지만 입력하고 tab 을 입력하면 나머지 fig가 자동으로 붙어서 ifconfig 가 완성됩니다
i 로 시작하는 명령어가 한개 이상인 상황에서 i 만 입력하고 tab 을 누를경우는 후보의 목록을 보여주기도 합니다
그런데 우리의 hello 명령어는 hel 까지만 치면 자동완성 되지 않습니다
이것은 그냥 터미널을 껏다가 다시 켜주면 해결됩니다

설치과정에서 일어난 일들

sudo npm install -g 명령어를 통해 설치과정에서 일어난 일은 다음과 같습니다
A. /usr/local/lib/node_modules 에 mcapp이라는 이름으로 mycliapp 폴더로 연결되는 링크파일을 생성합니다
이 링크파일을 생성하게되면
/Users/kst/mycliapp/
/usr/local/lib/node_modules/mcapp/
두 경로는 같은 경로가 됩니다
즉 /usr/local/lib/node_modules/mcapp/mycode.js 를 제거하면
/Users/kst/mycliapp/mycode.js 를 제거하는 셈인것이지요

B. /usr/local/bin 에 hello 라는 이름으로 /usr/local/lib/node_modules/mcapp/mycode.js 파일로 연결되는 링크파일을 생성합니다
/usr/local/bin 에 생성되는 파일들에는 내가 현재 어디에 위치하더라도 그냥 hello 라고 파일이름만 입력하면 실행시킬 수 있습니다

물론
/usr/local/bin/hello 는 /Users/kst/mycliapp/mycode.js 를 가리키고 있으니
/Users/kst/mycliapp/mycode.js 로 실행이 가능했던것과 마찬가지로 
/usr/local/bin/hello 라고 입력해서도 실행할 수도 있습니다

만약에
그렇다면 /usr/local/bin/hello 를 제거하면 /Users/kst/mycliapp/mycode.js 가 지워질까요?
sudo rm /usr/local/bin/hello 명령어로 hello 링크파일을 지울 수 있습니다.
지워도 /Users/kst/mycliapp/mycode.js 가 지워지는것은 아닙니다. [링크파일]이 지워진것입니다.

만약에
mycode.js 파일을 지우거나 이름을 바꾸거나 mycliapp 폴더를 제거하거나 이름을 바꿔서 hello 링크파일이 바라보는 실제 대상이 사라지게 한 뒤
hello 커맨드를 입력하면 실행이 정상적으로 될까요?
당연히 안됩니다
zsh: command not found: hello

만약에
sudo npm install -g 명령어로 설치하고 난 뒤에 /Users/kst/mycliapp/package.json 파일의 bin 부분의 
"bin":{ "hello":"./mycode.js"  } 를 "bin":{ "hello":"./mycode2.js"  } 로 바꾸거나 "bin":{ "hello2":"./mycode.js"  } 로 바꾸는 등의 변화를 준 후
hello 커맨드를 입력하면 실행이 정상적으로 될까요?
package.json 수정과는 상관없이 실행이 잘 됩니다

만약에
sudo npm install -g 명령어로 설치하고 난 뒤에 /Users/kst/mycliapp/mycode.js 의 코드내용을 변경하고 실행하면 변경사항이 반영될까?
console.log(12+34) 였던 모습을 console.log(12+35) 로 바꿔서 저장합니다
그리고 hello 를 실행합니다. 47이 출력됩니다. 반영됩니다.

만약에
sudo npm install -g 명령어로 설치한 것에 대해서 다시 uninstall 명령어로 제거한 뒤에
hello 커맨드를 입력하면 실행이 정상적으로 될까요?
참고로 uninstall 하는 명령어는 sudo npm uninstall mcapp -g 입니다.
mcapp은 우리의 앱의 이름이며 이것은 package.json 의 name 에 적혀있죠.
uninstall 후에는 hello 커맨드로 더 이상 실행이 안됩니다
uninstall 을 하게되면 일단 npm list -g 명령어로 나오는 설치된 앱 리스트에서 사라지게되죠
그리고 /usr/local/bin/ 에 있던 hello 링크파일과 /usr/local/lib/node_modules/ 에 있던 mcapp 링크파일이 사라집니다
링크파일들이 사라지니 hello 입력으로는 당연히 안되게 되는것입니다