make & Makefile 이란?

SHELL 에서 컴파일을 해보셨다면, make 명령어로 컴파일을 실행하는 경우를 자주 보셨을 것입니다. Makefile이 있는 디렉토리에서 make 만 치면 컴파일이 실행된다?? 어떻게 이런 일이 일어날 수 있는 것일까요? 

왜냐하면 make는 파일 관리 유틸리티 이기 때문이지요.

make

파일 간의 종속관계를 파악하여 Makefile( 기술파일 )에 적힌 대로 컴파일러에 명령하여 SHELL 명령이 순차적으로 실행될 수 있게 합니다.

그럼 이제 Makefile도 어떤 역할을 하는지 아시겠죠?

make를 쓰는 이유

하지만 여기서 의문점이 있을 수 있습니다. 그냥 컴파일러로 컴파일하면 되지 왜 굳이 Makefile을 만들고 make명령을 실행해야 하나?

make을 쓰면 다음과 같은 장점이 있습니다.

  1. 각 파일에 대한 반복적 명령의 자동화로 인한 시간 절약
  2. 프로그램의 종속 구조를 빠르게 파악 할 수 있으며 관리가 용이
  3. 단순 반복 작업 및 재작성을 최소화


글로만 보니 이해가 잘 안되시죠? 그럼 make의 필요성을 느껴보기 위해 기본적인 컴파일 과 make를 이용한 컴파일을 직접 해봅시다!

예제


이제 위의 종속관계 표를 보며 diary_exe라는 실행 파일을 만들어 봅시다!


1. diary.h 헤더파일 만들기

세 개의 c파일이 include 할 헤더파일을 생성해 봅시다!

vi diary.h ( 헤더 파일 생성)


코드 



2. 재료로 사용 될 C파일 만들기

vi memo.c 
vi calendar.c 
vi main.c

코드

  1. memo.c 
  2. calendar.c 
  3. main.c 



3. 생성된 파일 확인하기

위의 모든 파일을 생성 했다면 제대로 생성 되었는지 ls명령어로 확인해 줍시다.

$ ls 



자! 모든 파일을 생성했다면 이제 두가지 방법으로 컴파일을 해보겠습니다.


기본적인 컴파일 과정

먼저 기본적인 방법으로 컴파일을 해봅시다. 컴파일은 gcc 를 이용하였습니다.

1. c파일에서 object 파일 생성하기

아래의 명령어로

gcc -c -o memo.o memo.c 
gcc -c -o calendar.o calendar.c 
gcc -c -o main.o main.c

각 c파일에서 object 파일을 생성해 줍니다.

여기서 -c 옵션은 object 파일을 생성하는 옵션이고, 
-o 옵션은 생성 될 파일 이름을 지정하는 옵션입니다.

여기서는 -o 옵션을 넣지 않아도 object 파일이름이 (c파일이름).o로 자동 생성 됩니다. 
하지만 실행 파일 생성시 -o 옵션을 넣지 않으면 모든 파일이 a.out 이라는 이름을 가지게 되므로 여러 개의 실행 파일을 생성해야 할 때 효율적인 옵션입니다.


그럼 
ls 명령어로 object 파일이 제대로 생성되었는지 확인해 줍시다. 



2. 각 object파일을 묶어 컴파일을 통해 diary_exe 실행파일 생성하기

이제 실행 파일을 생성해 봅시다!

gcc -o diary_exe main.o memo.o calendar.o

여기서 object 파일들의 순서는 상관이 없습니다. 
위의 명령어를 실행하면 드디어 diary_exe 실행파일이 생성됩니다!!!!


ls 명령어로 확인해 봅시다. 


3. 결과 확인하기

바르게 생성되었다면 아래와 같이 결과가 나오는지 확인해 보세요.

$./diary_exe


기존의 컴파일 과정이 여기서는 그리 귀찮지 않습니다. 모든 c파일을 각각 컴파일 해도 3번만 명령해 주면 되니까요. 하지만 만약 하나의 실행파일을 생성하는데 필요한 c파일이 1000개라면..?? 1000개의 명령어가 필요합니다. 이러한 상황을 해결해 주는 것이 바로 make 와 Makefile입니다!


make를 이용한 컴파일 과정

그럼 이제 Makefile 을 먼저 어떻게 만드는지 알아 본 후 make 명령으로 위의 파일들을 컴파일 해봅시다.


Makefile 의 구성

Makefile은 다음과 같은 구조를 가집니다.

-목적파일(Target) : 명령어가 수행되어 나온 결과를 저장할 파일 
-의존성(Dependency) : 목적파일을 만들기 위해 필요한 재료 
-명령어(Command) : 실행 되어야 할 명령어들 
-매크로(macro) : 코드를 단순화 시키기 위한 방법


Makefile의 기본구조

위의 구성에서 말한 요소들은 실제 Makefile 코드에서 다음과 같이 배치됩니다.


Makefile 작성규칙

목표파일 : 목표파일을 만드는데 필요한 구성요소들 
(tab)목표를 달성하기 위한 명령 1 
(tab)목표를 달성하기 위한 명령 2

// 매크로 정의 : Makefile에 정의한 string 으로 치환한다. 
// 명령어의 시작은 반드시 으로 시작한다. 
// Dependency가없는 target도 사용 가능하다.


make 예제 따라해보기

자! 이제 실제로 Makefile을 만들어 봅시다~

$ vi Makefile

여기서 더미타겟 은 파일을 생성하지 않는 개념적인 타겟으로

$ make clean

라 명령하면 현재 디렉토리의 모든 object 파일들과 생성된 실행파일인 diary_exe를 rm 명령어로 제거해 줍니다.


이제

$ make

로 Makefile을 실행해 줍니다.




명령어들이 실행 되면서 타겟파일이였던 diary_exe 가 만들어졌습니다!!

실행결과는 기본적인 컴파일 과정에서 본 결과와 동일함을 알 수 있습니다.

그런데 아직까지 기본적인 컴파일 과정을 묶어둔 것 외에는 특별한 점이 없어 보입니다.

위의 코드를 더욱 단순화 시키기 위해서 매크로(macro)를 사용해 봐요~


Makefile 개선하기 : 매크로 사용

매크로는 생각보다 간단합니다. 위의 코드에서 중복되는 파일 이름들을 특정 단어로 치환하면 됩니다.

마치 C언어에서 #define을 하는 것과 비슷한 원리입니다.


Makefile 매크로 사용 예제


작성 규칙

  1. 매크로를 참조 할 때는 소괄호나 중괄호 둘러싸고 앞에 ‘$’를 붙인다.
  2. 탭으로 시작해서는 안되고 , :,=,#,”” 등은 매크로 이름에 사용할 수 없다.
  3. 매크로는 반드시 치환될 위치보다 먼저 정의 되어야 한다.

여기서 -W -Wall는 컴파일 시 컴파일이 되지 않을 정도의 오류라도 모두 출력되게 하는 옵션입니다.

make clean 
vi Makefile //매크로 사용 예제처럼 수정 
./diary_exe

로 전과 같은 결과가 나오는지 확인해 보세요~

여기서 더 코드를 단순화 시키기 위해서 사용자가 직접 정의하는 매크로가 아닌 미리 정의된 내부 매크로를 한번 사용해 보겠습니다!


Makefile 개선하기2 : 내부 매크로 사용



!? 
내부 매크로를 사용하였더니 코드가 굉장히 단순해 졌습니다! 
여기서 사용된 내부 매크로를 한번 살펴봅시다.

  1. “$@” : 현재 타겟의 이름
  2. “$^” : 현재 타겟의 종속 항목 리스트

이를 바탕으로 위의 코드를 한번 처음부터 끝까지 해석해 봅시다!

1. gcc 컴파일러를 이용 
2. 사소한 오류까지 출력 
3. 최종 타겟 파일은 diary_exe 
4. OBJECT 로 정의할 파일들은 memo.o main.o calendar.o 
5. all 은 현재는 사용하지 않았지만 타겟 파일이 여러개 일때 사용됩니다. 
6. 타겟 파일을 만들기 위해 OBJECT 들을 사용한다.( 단 OBJECT 파일이 없다면 OBJECT 파일과 이름이 동일한 C파일을 찾아 OBJECT파일을 생성한다. ) 
7. gcc -o diary_exe memo.o main.o calendar.o과 동일 
8. 더미타겟

이해가 되셨나요?


내부 매크로는 본 예제에서 쓰인 것 보다 훨씬 많기 때문에 리스트를 한번 찾아보고 다른 예제를 해보시면 도움이 됩니다 :-)


정리

이처럼 Makefile을 생성하여 make 명령을 사용하면 다음과 같은 장점이 있습니다.

  • 입력파일 변경 시 결과파일 자동 변경을 원할 때 지능적인 배치작업 수행
  • 일일이 gcc 명령어를 안치고도 간단하면서 용이하게 컴파일을 진행할 수 있음

우리 모두 make 로 더 쉽게 컴파일 해요~.~



출처: http://bowbowbow.tistory.com/12#기본적인-컴파일-과정 [멍멍멍]

5. VIM 에디터 이해 및 실습

5.1. VIM 에디터 이해 및 설치

  • VIM : Vi improved 에서 앞 글자를 빼내어 만든 이름
    • Vi: 전통적이 유닉스 에디터(개발자: 빌 조이), Visual Editor의 줄임말
    • Vim 은 Vi에 자동화, 시각화 메뉴등을 추가한 프로그램
    • Vim 이외에 이맥스(Emacs, GNU 프로젝트 설립자 리차드 스톨만이 개발) 라는 유명한 에디터가 있음 (대부분 개발자는 두 에디터 중 하나를 사용함)

5.2. ubuntu vim을 위한 한글 설정

  1. 시스템 언어 설정 확인 (기본 설정으로 POSIX, glibc에서의 기본 로케일은 C 또는 POSIX)
    (참고1: POSIX - 이식 가능 운영 체제 인터페이스의 약자로, 다양한 유닉스 계열 운영체제 간 공통 시스템콜 또는 API 정의)
    (참고2: glibc - GNU 프로젝트의 일환으로 개발된 표준 C언어 라이브러리로 C++언어도 지원)

    # locale
    
  2. 한글 입력 패키지 설치

    # sudo apt-get install language-pack-ko
    
  3. 시스템 언어 설정 변경

    # sudo locale-gen ko_KR.UTF-8
    
    - 확인: ko_KR.UTF-8 UTF-8 만 샵(#) 표시가 없어야 함
    # vi /etc/locale.gen
    
  4. 재부팅시 기본적으로 한글을 설정할 수 있도록 /etc/default/locale 파일에 다음 설정 추가

    LANG="ko_KR.UTF-8"
    LANGUAGE="ko_KR:ko:en_US:en"
    
  5. vi ~/.vimrc 에도 다음 두 줄 추가

    set encoding=utf-8
    set fileencodings=utf-8,euckr
    

5.3. vim 네 가지 모드

  • 일반(명령) 모드: 처음 vim을 실행했을 때 또는 입력 모드/명령 모드에서 ESC입력 시 - 찾기, 커서 이동등
  • 명령(명령행) 모드: 일반 모드에서 : 입력 시 - 저장, 파일읽기, vim설정등
  • 입력(편집) 모드: 일반 모드에서 a 또는 i 또는 o 키 입력 시 - 내용 입력

  • Visual 모드: 일반 모드에서 v 입력 시 - 블럭 복사/붙이기

커서 이동 (방향키로도 지원되는 경우가 많음)

k       커서를 위로 움직임
j       커서를 아래로 움직임
h       커서를 왼쪽으로 움직임
l       커서를 오른쪽으로 움직임
입력 모드 진입 (입력 모드 진입 시, 왼쪽 하단에 "--INSERT-- " 라는 문구가 출력)

o  포커스 잡힌 커서 아래 라인으로 이동 후 편집모드 시작  
O  포커스 잡힌 커서 윗 라인으로  이동 후 편집모드 시작  
i  포커스 잡힌 커서 위치에서 편집모드 시작  
I  포커스 잡힌 커서의 라인 제일 앞으로 이동 후 편집모드 시작  
a  포커스 잡힌 커서의 다음 문자열에서 편집모드 시작  
A  포커스 잡힌 커서의 라인 제일 뒤로 이동후 편집모드 시작
블록 지정 및 복사 (Visual 모드에서 활용)

v          단어 단위로 블럭 지정.  
Shift + v  라인 단위로 블럭 지정.
y          지정된 블럭을 복사.   
p          복사된 블럭을 현재 커서에 붙인다.
u          직전 실행 작업 취소

자주 사용하는 시나리오
1. v 로 visual 모드로 들어간 후
2. Shift 를 누른채 커서 이동을 통해 블록 지정
3. y 를 눌러 블록 복사
4. 붙이기 필요한 곳으로 커서 이동 후 p 를 눌러 복사된 블록 붙이기
편집 

x          커서의 한 문자를 삭제한다.  
dd         커서의 현재 라인을 삭제한다. 
Shift + j  커서의 아랫라인과 현재 라인을 하나의 라인으로 합침
문자열 찾기 기능

일반 모드에서 / 를 누른 후 찾을 문자 입력 
정규 표현식 지원 (다음 기호는 a\+ 와 같이 백슬래시와 함께 사용해야 함)
+ : 1번 이상의 임의 번 반복. a+ 는 a, aa, aaa, ... 즉 aa* 와 동일.
| : a|b 는 a 또는 b
() : group, (ab|cd)ef 는 abef 또는 cdef
? : 없거나 하나 있거나. ab? 는 a 또는 ab

찾을 문자 입력 후 엔터 누르면 해당 문자열 색상 변경을 통한 표시

이 상태에서

n          다음 찾는 문자열로 이동
N          이전 찾는 문자열로 이동

참고: 파이썬과 정규표현식(https://wikidocs.net/4308)

문자열 교체 기능(명령 모드)

:(시작줄),(끝줄)s/찾을패턴/바꿀문자열/옵션

옵션 :
g : global - 한 줄에 패턴이 여러 번 나오면 모두 바꿈, 지정하지 않으면 첫번째 패턴만 치환
i : ignore case - 대소문자 구분을 하지 않음
c : confirm - 검색된 모든 문자열에 대해서 치환 여부에 대해 사용자 확인을 받음

예)
:5,10s/a/b/                5번째 줄부터 10번째 줄까지 각 줄의 첫번째 "a" 를 "b" 로 치환
:.,.+10s/a/b/g             현재 줄부터 (현재 행번호+10) 번째 줄까지 모든 "a" 를 "b" 로 치환
:1,$s/a/b/c                첫 번째 줄부터 마지막 줄까지 (즉 문서 전체) 각 줄의 "a" 를 "b" 로 바꾸되, 사용자에게 확인을 받음
:%s/a/b/gi                 문서 전체에서 "a" 와 "A" 를 "b" 로 치환
:%s/Hello/Good Morning/g   두 글자 이상의 문자열도 검색 및 치환 가능
파일 열기 및 저장

:e filename                filename 의 파일이 존재하면 오픈하고, 존재하지 않으면 해당 파일 이름으로 새로 파일을 만들고 오픈함
:w                         현재 오픈된 파일 저장
:q                         저장하지 않고 종료 (quit)
:wq                        현재 오픈된 파일 저장 후 종료
:wq {저장할 파일명}        현재 오픈된 파일을 저장할 파일명으로 저장 후 종료
:q!                        강제 종료 (대소문자 구문)
:wq!                       현재 오픈된 파일 강제 저장 및 종료

5.4. vim 설정

  • 명령(명령행) 모드에서 set all 입력 (결국 :set all 입력 후 엔터)
    • vim에서 설정할 수 있는 모든 옵션이 나옴
  • ~/.vimrc 파일에 필요한 vim 설정을 할 수 있음

실습 - vi 사용
- vi ~/.vimrc 후 다음 설정 입력 및 저장
 set nocompatible
 set autoindent
 set cindent
 set smartindent
 set wrap
 set nowrap
 set nowrapscan
 set nobackup
 set ruler
 set shiftwidth=4
 set number
 set fencs=utf-8
 set fileencoding=utf-8
 set tenc=utf-8
 set expandtab
 set hlsearch
 set ignorecase
 set tabstop=4
 set incsearch
 syntax on
 filetype indent on
 set background=dark
 colorscheme desert
 set backspace=eol,start,indent
 set history=1000

5.5. vim 팁

  • 한글 작성 중 한글이 깨져보일 시
    • sudo apt-get install language-pack-ko
    • sudo locale-gen ko_KR.UTF-8
    • sudo dpkg-reconfigure locales
    • vi ~/.vimrc 에서 아래 두 줄 추가
      • set encoding=utf-8
      • set fileencodings=utf-8,euckr


4. Ubuntu(우분투) 이해하기

4.1. ubuntu 배포판

  • 다양한 배포판 중 하나
  • 데비안 배포판을 기반으로 캐노니컬 사가 우분투 배포판 개발
    • 데비안 배포판은 apt 프로그램을 이용해서 소프트웨어 설치 및 업데이트를 간편하게 한 패키지
  • 우분투 의미: 남아프리카 부족 언어로 '너가 있으니 나도 있다' 라는 의미
    • 우분투 데스크탑 배포판 (X윈도우 기반, GUI환경 기본 제공) 과 우분투 서버 배포판, 두 가지 기본 배포판을 제공
    • 지원 기간이 짧은 일반 버전과 지원기간이 장기(5년)인 LTS(Long Term Support) 버전으로 나눠서 발표

4.2. ubuntu 패키지 관리자

  • CentOS나 Fedora 과 같은 RedHat 계열 배포판은 RPM 이라는 패키징 시스템을 사용함
  • ubuntu와 같이 데비안 계열 배포판은 deb 라는 패키징 시스템을 사용함

  • 패키지와 패키지 정보를 저장하고 있는 패키지 저장소라는 개념을 가지고 있음

  • 소프트웨어 패치, 추가등 정보를 관리
  • 우분투 사용자가 패키지 관리자를 통해 패키지 저장소에 접근하면, 소프트웨어 변경사항을 알려주고 업데이트, 다운로드등을 지원

4.3. ubuntu 패키지 관리 실무

  • ubuntu PC에 설치된 패키지(소프트웨어) 확인 방법
      # dpkg -l
    
  • ubuntu PC에 설치된 특정 패키지(소프트웨어) 확인 방법
      # dpkg -l | grep 패키지명(소프트웨어명)
    
  • ubuntu 패키지 인덱스 정보 업데이트 (배포판 버전에 따른 패키지 업데이트 버전 정보 등)
      # sudo apt-get update
    
  • 설치된 ubuntu 패키지 업그레이드
      # sudo apt-get upgrade
    
  • 패키지 설치
      # sudo apt-get install 패키지명
    
  • 패키지 재설치
      # sudo apt-get --reinstall install 패키지명
    
  • 패키지 삭제(설정파일 제외)
      # sudo apt-get remove 패키지명
    
  • 패키지 삭제(설정파일 포함)
      # sudo apt-get --purge remove 패키지명
    
  • 패키지 소스코드 다운로드
      # sudo apt-get source 패키지명
    
  • 패키지 검색
      # sudo apt-cache search 패키지명
    
  • 패키지 검색
      # sudo apt-cache show 패키지명
    
  • 패키지 저장소 설정
    • apt-get 패키지 저장소는 /etc/apt/sources.list 파일에 있음


3. 쉘 스크립트

  • 쉘을 사용해서 프로그래밍을 할 수 있음
  • 서버 작업 자동화를 위해 기본적으로 익혀둘 필요가 있음
  • 기본 명령어를 기반으로 하며, 이에 몇 가지 문법이 추가되는 형태로, 일반적인 프로그래밍 언어와는 달리 간단하고, 쉽게 응용 가능

3.1. 기본 문법

  • 쉘 스크립트는 파일로 작성 후, 파일을 실행
  • 파일의 가장 위의 첫 라인은 "#! /bin/bash" 로 시작
  • 쉘 스크립트 파일은 실행 권한을 가지고 있어야 함
  • 일반적으로 '파일이름.sh' 와 같은 형태로 파일 이름을 작성함
실습
bash 쉘에서 제공하는 echo 함수를 이용하여 화면에 "Hello bash" 를 출력 할 수 있도록 스크립트 작성
# cd ~
# vi test.sh

다음과 같이 작성
#! /bin/bash

echo "Hello bash"
# ls -al
drwx------ 1 root root 4096 Oct  8 15:27 .
drwxr-xr-x 1 root root 4096 Oct  8 07:35 ..
-rw-r--r-- 1 root root   32 Oct  8 15:27 test.sh
# chmod +x test.sh
# ./test.sh
Hello bash
#

주석

# 기호로 시작하는 라인은 주석처리
예)
# This is comment

변수

  • 선언
    • 변수명=데이터
    • 변수명=데이터 사이에 띄어쓰기는 허용되지 않음
  • 사용
    • $변수명 으로 사용됨
예)
#!/bin/bash

mysql_id='root'
mysql_directory='/etc/mysql'

echo $mysql_id
echo $mysql_directory

리스트 변수 (배열)

  • 선언
    • 변수명=(데이터1 데이터2 데이터3 ...)
  • 사용
    • ${변수명[인덱스번호]}
#! /bin/bash

daemons=("httpd" "mysqld" "vsftpd")
echo ${daemons[1]}        # $daemons 배열의 두 번째 인덱스에 해당하는 mysqld 출력
echo ${daemons[@]}        # $daemons 배열의 모든 데이터 출력
echo ${daemons[*]}        # $daemons 배열의 모든 데이터 출력 
echo ${#daemons[@]}       # $daemons 배열 크기 출력

filelist=( $(ls) )        # 해당 쉘스크립트 실행 디렉토리의 파일 리스트를 배열로 $filelist 변수에 입력
echo ${filelist[*]}       # $filelist 모든 데이터 출력

사전에 정의된 지역 변수

$$ : 쉘의 프로세스 번호
$0 : 쉘스크립트 이름
$1 ~ $9 : 명령줄 인수
$* : 모든 명령줄 인수리스트
$# : 인수의 개수

연산자

  • expr : 숫자 계산
  • expr 를 사용하는 경우 역작은 따옴표( ` )를 사용해야 함(작은 따옴표가 아님)
  • 연산자 *와 괄호() 앞에는 역슬래시()와 같이 사용
  • 연산자와 숫자, 변수, 기호 사이에는 space를 넣어야 함
    예)
    num=`expr \( 3 \* 5 \) / 4 + 7`
    echo $num
    

조건

  • 조건 작성이 다른 프로그래밍 언어와 달리 가독성이 현저히 떨어짐, 필요할 때마다 참조하면 됨!
  • 문자 비교
    문자1 == 문자2            # 문자1 과 문자2가 일치
    문자1 != 문자2            # 문자1 과 문자2가 일치하지 않음
    -z 문자                   # 문자가 null 이면 참
    -n 문자                   # 문자가 null 이 아니면 참
    문자 == 패턴              # 문자열이 패턴과 일치
    문자 != 패턴              # 문자열이 패턴과 일치하지 않음
    
  • 수치 비교 ( <, > 는 if 조건시 [[ ]] 를 넣는 경우 정상 동작하기도 하지만, 기본적으로 다음 문법을 사용하는 것을 권장)
    값1 -eq 값2             # 값이 같음(equal)
    값1 -ne 값2             # 값이 같지 않음(not equal)
    값1 -lt 값2             # 값1이 값2보다 작음(less than)
    값1 -le 값2             # 값1이 값2보다 작거나 같음(less or equal)
    값1 -gt 값2             # 값1이 값2보다 큼(greater than)
    값1 -ge 값2             # 값1이 값2보다 크거나 같음(greater or equal)
    값1 -gte 값2            # 값1이 값2보다 크거나
    
  • 파일 검사
    -e 파일명               # 파일이 존재하면 참
    -d 파일명               # 파일이 디렉토리면 참
    -h 파일명               # 심볼릭 링크파일
    -f 파일명               # 파일이 일반파일이면 참
    -r 파일명               # 파일이 읽기 가능이면 참
    -s 파일명               # 파일 크기가 0이 아니면 참
    -u 파일명               # 파일이 set-user-id가 설정되면 참
    -w 파일명               # 파일이 쓰기 가능 상태이면 참
    -x 파일명               # 파일이 실행 가능 상태이면 참
    
  • 논리 연산
    조건1 -a 조건2         # AND
    조건1 -o 조건2         # OR
    조건1 && 조건2         # 양쪽 다 성립
    조건1 || 조건2         # 한쪽 또는 양쪽다 성립
    !조건                  # 조건이 성립하지 않음
    true                   # 조건이 언제나 성립
    false                  # 조건이 언제나 성립하지 않음
    

조건문 문법

  • 기본 if/else 구문

    if [ 조건 ]
    then
      명령문
    else
      명령문
    fi
    
    예)
    #!/bin/bash
    ping -c 1 192.168.0.1 1> /dev/null
    if [ $? == 0 ]
    then
      echo "게이트웨이 핑 성공!"
    else
      echo "게이트웨이 핑 실패!"
    fi
    
  • 기본 if 구문

    if [ 조건 ]
    then
      명령문
    fi
    
    예)
    #!/bin/bash
    if [[ $1 != $2 || -z $2 ]]
    then
      echo "입력한 값이 일치하지 않습니다."
      exit
    fi
    
  • 기본 if 구문 (한 라인에 작성하는 방법)

    if [ 조건 ]; then 명령문; fi
    
    예)
    if [[ -z $1 ]]; then echo "인수를 입력하세요"; fi
    
  • if [ 뒤와, ] 앞에는 반드시 공백이 있어야 함

  • [ ] 에서 &&, ||, <, > 연산자들이 에러가 나는 경우는 [[ ]] 를 사용하면 정상 작동하는 경우가 있음

반복문 문법

  • 기본 for 구문

    for 변수 in 변수값1 변수값2 ...
    do
      명령문
    done
    
    예1)
    #!/bin/bash
    for database in $(ls)
    do
      echo ${database[*]}
    done
    
    예2)
    #!/bin/bash
    for database in $(ls); do
      echo ${database[*]}
    done
    
    예3)
    #!/bin/bash
    for database in $(ls); do echo ${database[*]}; done
    
  • 기본 while 구문

    while [ 조건문 ]
    do
      명령문
    done
    
    예)
    #!/bin/bash
    lists=$(ls)
    num=${#lists[@]}
    index=0
    while [ $num -ge 0 ]
    do
      echo ${lists[$index]}
      index=`expr $index + 1`
      num=`expr $num - $index`
    done


2. 리눅스 쉘(bash), 기본 명령어 이해 및 실습

2.1. 쉘 종류

  • 쉘(shell)
    • 운영체제 커널과 사용자 사이를 이어주는 역할
    • 사용자의 명령을 해석하고, 커널에 명령을 요청해주는 역할 

  • 유닉스/리눅스 쉘 종류
    • Bourne-Again Shell (bash) : GNU 프로젝트의 일환으로 개발됨, 리눅스 거의 디폴트임
    • Bourne Shell (sh)
    • C Shell (csh)
    • Korn Shell (ksh) : 유닉스에서 가장 많이 사용됨

2.2. 리눅스 기본 명령어 정리

  • 리눅스 명령어는 결국 쉘이 제공하는 명령어임
  • 리눅스 기본 쉘이 bash 이므로, bash에서 제공하는 기본 명령어를 배우는 것임 

  • whoami : 로그인한 사용자 ID를 알려줌

    # whoami
    root
  • passwd : 로그인한 사용자 ID의 암호 변경

    # passwd
    Enter new UNIX password:
    Retype new UNIX password:
    passwd: password updated successfully
  • pwd : 현재 디렉토리 위치

    # pwd
    /
  • cd : 디렉토리 이동

# pwd
/etc
# cd ~
# pwd
/root
# cd -
# pwd
/etc
  • ls : 파일 목록 출력
# ls -al
total 32
drwxr-xr-x 4 root root 4096 Oct  3 09:51 .
drwxr-xr-x 1 root root 4096 Oct  4 03:52 ..
drwxr-xr-x 2 root root 4096 Oct  3 09:47 conf.d
-rwxr-xr-x 1 root root  120 Jul 19 19:28 debian-start
-rw------- 1 root root  317 Oct  3 09:47 debian.cnf
lrwxrwxrwx 1 root root   24 Oct  3 09:47 my.cnf -> /etc/alternatives/my.cnf
-rw-r--r-- 1 root root  839 Jan 21  2017 my.cnf.fallback
-rw-r--r-- 1 root root  682 Feb  3  2017 mysql.cnf
drwxr-xr-x 2 root root 4096 Oct  3 12:47 mysql.conf.d
  • 와일드 카드
    • * 는 임의 문자열
    • ? 는 문자 하나
# ls debi* -al
-rwxr-xr-x 1 root root 120 Jul 19 19:28 debian-start
-rw------- 1 root root 317 Oct  3 09:47 debian.cnf
  • cat : 파일 보기

    # cat mysql.cnf
    mysql.cnf 파일 내용이 출력됨
  • head/tail : head 는 파일 시작부분, tail 은 끝 부분을 보여줌

    # head mysql.cnf
    mysql.cnf 파일 앞부분만 출력됨 (기본적으로 출력 라인 수가 10으로 정해져 있음)
    # tail mysql.cnf
    mysql.cnf 파일 뒷부분만 출력됨 (기본적으로 출력 라인 수가 10으로 정해져 있음)
  • more : 파일 보기 (화면이 넘어갈 경우, 화면이 넘어가기 전까지 보여줌)

    # more mysql.cnf
    mysql.cnf 파일 내용이 출력됨
  • rm : 파일 및 폴더 삭제

    • 주로 사용하는 명령어 형태: rm -rf
    • r 옵션: 하위 디렉토리를 포함한 모든 파일 삭제
    • f 옵션: 강제로 파일이나 디렉토리 삭제 

  • man
    • manual이라는 의미. man rm을 입력하면 메뉴얼이 나옴

2.3. 리눅스 리다이렉션(redirection) 과 파이프(pipe)

  • standard stream
    • command 로 실행되는 process 는 세 가지 스트림을 가지고 있음
      • 표준 입력 스트림 (standard input stream)
      • 표준 출력 스트림 (standard output stream)
      • 오류 출력 스트림 (standard error stream)
    • 모든 스트림은 일반적인 plain text로 console 에 출력하도록 되어 있음 

  • 리다이렉션(redirection)
    • 스트림 흐름을 바꿔주는 것으로 > 또는 < 을 사용함
      1. ls > files.txt
        • ls 로 출력되는 표준 출력 스트림의 방향을 files.txt 로 바꿔줌 (files.txt 에 ls 로 출력되는 결과가 저장됨)
      2. head < files.txt
        • files.txt 의 파일 내용이 head 라는 파일의 처음부터 10 라인까지 출력해주는 명령으로 넣어짐 (files.txt 의 앞 10 라인이 출력됨)
      3. head < files.txt > files2.txt
        • files.txt 의 파일 내용이 head 로 들어가서, files.txt 의 앞 10 라인을 출력
        • head 의 출력 스트림은 다시 files2.txt 로 들어감
        • head 는 files.txt 내용을 출력하지 않고, 해당 출력 내용이 다시 files2.txt 에 저장됨(결과적으로 files.txt 의 앞 10 라인이 files2.txt에 저장됨)
      4. 기존 파일에 추가는 >> 또는 << 사용
        • ls >> files.txt
        • 기존에 있는 files.txt 파일 끝에, ls 출력 결과를 추가해줌


  • 파이프(pipe)
    • 두 프로세스 사이에서 한 프로세스의 출력 스트림이 또다른 프로세스의 입력 스트림으로 사용될 때 쓰임
      1. ls | grep files.txt
        • ls 명령을 통한 출력 내용이 grep 명령의 입력 스트림으로 들어감
        • grep files.txt 는 grep 명령의 입력 스트림을 검색해서 files.txt 가 들어 있는 입력 내용만 출력해줌
        • 따라서, ls 명령으로 해당 디렉토리/파일 중에 files.txt 파일이 있는지를 출력해줌
    • grep : 검색 명령
      • grep [-option] [pattern] [file or directory name]
        <option>
          -i : 영문의 대소문자를 구별하지 않는다.
          -v : pattern을 포함하지 않는 라인을 출력한다.
          -n : 검색 결과의 각 행의 선두에 행 번호를 넣는다(first line is 1).
          -l : 파일명만 출력한다.
          -c : 패턴과 일치하는 라인의 개수만 출력한다.
          -r : 하위 디렉토리까지 검색한다.
      • 사용 예
        • grep python files.txt -> files.txt 라는 파일에서 python 라는 문구가 들어간 모든 행을 출력
        • grep -n python files.txt -> files.txt 라는 파일에서 python 라는 문구가 들어간 모든 행을 라인까지 출력
        • grep -r python foldername -> foldername 라는 폴더내의 모든 파일 중 python 라는 문구가 들어간 행을 출력
        • grep -i python files.txt -> files.txt 라는 파일에서 python 라는 문구를 대,소문자 구분 없이 검색해서 출력
        • grep -E "go|java|python" files.txt -> files.txt 라는 파일에서 go, java, 또는 python 이 있는 모든 행을 출력

2.4. 리눅스 프로세스

  • 리눅스 프로세스
    • 프로세스는 실행 중인 프로그램을 의미
      • 좀더 깊게 이해한다면!
        • 프로세스는 메모리에 적재된 코드(바이너리) 이미지와 가상화된 메모리(가상 메모리)의 인스턴스, 열린 파일 같은 커널 리소스, 관련된 사용자 정보와 같은 보안 정보, 하나 이상의 스레드를 포함
    • 리눅스는 프로세스가 프로그램 실행 단위 (스케쥴링 단위)
      • 프로세스 ID(pid) 라는 unique한 ID를 부여받고, pid를 활용해서 프로세스를 제어
    • 리눅스는 기본적으로 다양한 프로세스가 실행됨
      • 유닉스 철학과 관련: 각 프로그램은 하나의 일을 잘 할 수 있게 만들 고, 새로운 기능이 필요하면, 기존 프로그램에 추가하지 말고, 새로운 프로그램을 만들 것.
      • 여러 프로그램이 서로 유기적으로 각자의 일을 수행하면서 전체 시스템이 동작하도록 하는 모델 

  • foreground process / background process
    • foreground process: 쉘(shell)에서 해당 프로세스 실행을 명령한 후, 해당 프로세스 수행 종료까지 사용자가 다른 입력을 하지 못하는 프로세스
    • background process: 사용자 입력과 상관없이 실행되는 프로세스
      • 쉘(shell)에서 해당 프로세스 실행시, 맨 뒤에 & 를 붙여줌
      • 사용 예
        # find / -name '*.py' > list.txt &
        [1] 57
      • [1] 은 작업 번호 (job number), 57 은 pid (process ID) 를 나타냄 

  • foreground process 제어하기

    - [CTRL] + z : foreground 프로세스를 실행 중지 상태(suspend 모드)로 변경
      - 맨 마지막 [CTRL] + z 로 중지된 프로세스는 bg 명령으로 background 프로세스로 실행될 수 있음
      - jobs 명령어 : 백그라운드로 진행 또는 중지된 상태로 있는 프로세스를 보여줌
    ```
    # find / -name '*.txt'
    ^Z
    [1]-  Stopped                 find / -name '*.txt'
    # find / -name '*.py'
    ^Z
    [2]-  Stopped                 find / -name '*.py'
    # jobs
    [1]-  Stopped                 find / -name '*.txt'
    [2]+  Stopped                 find / -name '*.py'
    # bg
    [2]+ find / -name '*.py' &
    ```
    - [CTRL] + c : 프로세스 작업 취소 (해당 프로세스는 완전히 종료됩니다.)
  • 프로세스 중지시키기

    • kill 명령어
      • 사용법
        1. kill % 작업 번호(job number)
        2. kill 프로세스 ID(pid)
        3. 작업 강제 종료 옵션 -9
          • # find / -name '*.py' > list.txt &
            [1] 57
            # kill -9 57
  • 프로세스 상태 확인

    • ps 명령어
    • 사용법 : ps [option(s)]
    • option(s)
      -a : 시스템을 사용하는 모든 사용자의 프로세스 출력 (보통 aux 와 같이 u, x 옵션과 함께 사용)
      -u : 프로세스 소유자에 대한 상세 정보 출력
      -l : 프로세스 관련 상세 정보 출력
      -x : 터미널에 로그인한 후 실행한 프로세스가 아닌 프로세스들도 출력함. 주로 데몬 프로세스(daemon process)까지도 확인하기 위해 사용함. 본래 ps 명령은 현재 쉘(shell)에서 실행한 프로세스들만 보여주기 때문에 이 옵션을 사용하는 경우가 많음
      -e : 해당 프로세스와 관련된 환경 변수 정보도 함께 출력
      -f : 프로세스 간 관계 정보도 출력
    • 데몬 프로세스(daemon process): daemon은 악마를 의미함. 사용자 모르게 시스템 관리를 위해 실행되는 프로세스로 보통 시스템이 부팅될 때 자동 실행 (예: ftpd, inetd 등) </pre>
    • ps 출력 정보 항목
      USER : 프로세스를 실행시킨 사용자 ID
      PID : 프로세스 ID
      %CPU : 마지막 1분 동안 프로세스가 사용한 CPU시간의 백분율
      %MEM : 마지막 1분 동안 프로세스가 사용한 메모리 백분율
      VSZ : 프로세스가 사용하는 가상 메모리 크기
      RSS : 프로세스에서 사용하는 실제 메모리 크기
      TTY : 프로세스와 연결된 터미널 포트
      STAT : 프로세스 상태
      START : 프로세스가 시작된 시간
      TIME : 현재까지 사용된 CPU 시간(분:초)
      COMMAND : 명령어
      
  • 프로세스 실행 권한

    • sudo 명령어 : root 계정으로 로그인 하지 않은 상태에서 root 권한이 필요한 명령을 실행할 수 있도록 하는 프로그램
      • 기본 사용법
        • sudo 명령어
      • 사용 예
        • sudo apt-get update
      • /etc/sudoers 설정 파일에서 다음과 같이 설정을 변경할 수 있음
        (visudo 를 쉘에서 명령하면, 해당 설정 파일이 오픈되어 수정 가능함, 물론 통상 root 권한으로 수정)
        1. 특정 사용자가 sudo를 사용할 수 있도록 설정
           userid       ALL=(ALL)       ALL
        2. 특정 그룹에 포함된 모든 사용자가 sudo를 사용할 수 있도록 설정
           %group        ALL=(ALL)       ALL
        3. 패스워드 생략 설정
           %group        ALL=(ALL)       NOPASSWD: ALL
           userid        ALL=(ALL)       NOPASSWD: ALL
        
  • 주로 사용하는 프로세스 명령 (적어도 이 명령은 편하게 사용해야 함)
    • ps aux | grep 프로세스명 : 프로세스가 실행 중인지를 확인하고, 관련 프로세스에 대한 정보 출력
    • kill -9 프로세스 ID(pid) : 해당 프로세스를 강제로 죽임
    • 명령 & : 터미널에서 다른 작업을 해야하거나, 프로세스 실행에 오랜 시간이 걸릴 경우 background 로 실행
    • [CTRL] + z : 프로세스 중지
    • [CTRL] + c : 프로세스 종료(실행 취소)


1. 리눅스 기본 이해

1.1. 초간단 리눅스 배경 이해

  • 컴퓨터의 운영체제 중 하나로 리누스 토르발스(Linus Torvalds)에 의해 시작된 다중 사용자, 다중 작업을 지원하는 유닉스(UNIX)와 유사한 운영체제 

  • GNU 프로젝트

    • GNU = Gnu is not Unix
    • 유닉스(UNIX) 운영체제를 여러 회사에서 각자 개발하며, 소스를 공유하지 않는 문화에 반발
    • 리차드 스톨먼이라는 사람이 초기 컴퓨터 개발 공동체의 상호협력적인 문화로 돌아갈 것을 주장하며 1985년 3월에 GNU 선언문을 발표
    • GNU 프로젝트를 지원하기 위해 자유 소프트웨어 재단(FSF) 설립과 GNU 공개 라이선스(GPL)라는 규약 제공 

  • GNU 프로젝트와 리눅스

    • 초기 운영체제 개발에 필요한 라이브러리, 컴파일러, 에디터, 유닉스 쉘 개발
    • 이를 지원하는 운영체제 커널 개발 시도 (GUN Hurd: https://ko.wikipedia.org/wiki/GNU_%ED%97%88%EB%93%9C)
    • 리누스 토발즈가 리눅스 커널 발표. 이를 GNU 프로젝트에서 수용하면서, GNU 프로젝트 산출물과 통합 및 개발 지속 

  • 리눅스 특징

    1. 유닉스 기반
      • 리눅스 커널 자체가 유닉스의 미닉스(Minix)를 참고하여 개발 

    2. 다중 사용자와 멀티 태스킹을 지원
      • 리눅스는 다중 사용자 (하나의 컴퓨터에 여러 사용자가 로그인 및 사용 가능) 와 멀티 태스킹(한번에 여러 프로세스 실행 가능)을 지원 

    3. 자유 소프트웨어
      • 리눅스 자유 소프트웨어 라이센스
      • 누구나 소스 코드 활용 및 수정, 재배포 가능
      • 리눅스 커널 및 관련 다양한 소프트웨어를 패키지로 묶어서 배포하는 것을 리눅스 배포판이라고 함(예: ubuntu)

1.2. 초간단 리눅스 구조

  • 리눅스는 리눅스 커널 + 쉘 + 컴파일러 + 다양한 소프트웨어를 포함한 하나의 패키지를 지칭
     

  • 다양한 소프트웨어가 리눅스 커널이 관리하고 있는 시스템 자원을 마구 사용할 경우, 시스템 안정성에 심각한 문제가 초래됨
  • 운영체제가 시스템 자원을 관리하고, 다양한 소프트웨어는 리눅스 커널이 제공하는 시스템 콜을 통해 시스템 자원 사용을 요청
  • 시스템 콜은 쉘, 다양한 언어별 컴파일러, 라이브러리를 통해 호출되게 됨
  • 리눅스 커널은 시스템 자원을 관리
    ■ 프로세스 관리(Process Management)
    ■ 메모리 관리(Memory Management)
    ■ 파일 시스템 관리(File System Management)
    ■ 디바이스 관리(Device Management)
    ■ 네트워크 관리(Network Management)


어제 작성한 geth 설치 명령어 집합과 조건문의 조합으로 새 컴퓨터에서 한방에 geth를 구축하는 스크립트를 만들어보자.

자, 우리는 s1과 s2의 root에 외부에서 로그인 할 수 있게 했고(permitrootlogin = yes) s1에서 s2에 루트가 아니게 로그인 할 때에는 공개키를 두고 왔기 때문에 비밀번호 없이 접속이 가능하다.

하지만 루트s1에서 루트s2로 로그인 할 대에는 비밀번호가 여전히 필요하다.

이를 sshpass라는 프로그램을 설치해 사용자 개입 없이 통과시켜보자.

일단, s1의 root 계정에서 _setting 폴더를 만들고 그 안에 아래와 같이 sh 파일을 만든다.

root@s1:~/_setting# touch installSshpass.sh
root@s1:~/_setting# chmod +x installSshpass.sh

x 권한을 루트에 부여하고, 서브라임텍스트의 file - browse server - s1 - _setting - installSshpass.sh - edit 을 누른다.

그리고 아래를 입력해준다.

#!/bin/bash
tmp='which sshpass'
if [[ ${#tmp}=0 ]]; then
    echo ==========install_sshpass==========
    apt-get install -y sshpass
fi

(sshpass를 설치해주는 스크립트)


root@s1:~/_setting# ./installSshpass.sh
==========install_sshpass==========
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following NEW packages will be installed:
  sshpass
0 upgraded, 1 newly installed, 0 to remove and 4 not upgraded.
Need to get 10.5 kB of archives.
After this operation, 56.3 kB of additional disk space will be used.
Get:1 http://kr.archive.ubuntu.com/ubuntu xenial/universe amd64 sshpass amd64 1.05-1 [10.5 kB]
Fetched 10.5 kB in 0s (298 kB/s)
Selecting previously unselected package sshpass.
(Reading database ... 217999 files and directories currently installed.)
Preparing to unpack .../sshpass_1.05-1_amd64.deb ...
Unpacking sshpass (1.05-1) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up sshpass (1.05-1) ...
root@s1:~/_setting#


정상적으로 sshpass가 설치되는 것을 볼 수 있다.

이제, 우리는 비밀번호를 입력해 sshpass로 s2의 모든 파일들에 접근할 수 있다.


root@s1:~/_setting# sshpass -p 111111 ssh s2 ls /
bin
boot
cdrom
dev
etc
home
initrd.img
initrd.img.old
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old


그러면, 이제 ls 대신에 geth를 구축하는 스크립트를 실행시키면 될 것이다.

먼저 그러려면 s2에 그 파일을 놓고 와야한다.


root@s1:~# ls
my.sh  _setting  xx.tar
root@s1:~# sshpass -p 111111 scp my.sh s2:/root/


Sshpass -p 비밀번호 scp 파일명 보낼이:폴더

를 입력하면 파일을 전송할 수 있다.


root@s1:~# sshpass -p 111111 ssh s2 ls


이처럼 s2에 파일이 전송된 것을 확인할 수 있다.

본격적으로 스크립트를 넘기기 전에 먼저 s2에 공개키를 넘기는 스크립트를 짜자.

ssh-keygen -N '' -f ~/.ssh/id_rsa

를 입력하면, 공개키가 생성되어 /.ssh/id_rsa라는 파일에 저장이 된다.


root@s1:~/_setting# ssh-keygen -N '' -f ~/.ssh/id_rsa
Generating public/private rsa key pair.
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:sO/Y4xn3M3+HY69wNGNEONODuJiMHrb6RoIO2FEpCbU root@s1
The key's randomart image is:
+---[RSA 2048]----+
|.o.. .     . +.  |
|  o.o     . =.o  |
|  Eo  .o o . o.. |
|  .   +o+ .  .   |
|.. o o.oS     =  |
|o o . +.     o o |
| o   +  o . . .. |
|  . . .+.+ .oo+ o|
|     oo.=.  .=o=o|
+----[SHA256]-----+


먼저 ssh_keygen.sh 를 만들어 공개키를 저장하고, 공개키를 보내는 스크립트 sendKeys.sh를 만들자.


root@s1:~/_setting# touch ssh_keygen.sh
root@s1:~/_setting# chmod +x ssh_keygen.sh
root@s1:~/_setting# touch sendKeys.sh
root@s1:~/_setting# chmod +x sendKeys.sh
root@s1:~/_setting# ls


Ssh_keygen.sh 안에는 공개키를 저장할 것인데, 서브라임텍스트를 통해 저장할 스크립트는 아래와 같다.

#!/bin/bash

rm -rd ~/.ssh
mkdir ~/.ssh
ssh-keygen -N '' -f ~/.ssh/id_rsa

자, 다음은 우리가 작업할 대상인 두대의 가상머신의 ip를 hosts에 저장하자.

root@s1:~/_setting# cat >> hosts << EOF
> 192.168.56.70
> 192.168.56.77
> EOF
root@s1:~/_setting# cat hosts
192.168.56.70
192.168.56.77


다음은 서브라임텍스트에서 sendKeys.sh를 열어주자.

#!/bin/bash
~/_setting/installSshpass.sh
~/_setting/ssh_keygen.sh

for ip in `cat ~/_setting/hosts`; do
    sshpass -p 111111 ssh-copy-id -oStrictHostKeyChecking=no $ip
done

이러면, 키 값을 넘길 떄 호스트키의 핑거프린트를 만들겠냐는 질문 없이 공개키를 잘 넘긴다.

실행해보자.


root@s1:~/_setting# ./sendKeys.sh
==========install_sshpass==========
Reading package lists... Done
Building dependency tree      
Reading state information... Done
sshpass is already the newest version (1.05-1).
0 upgraded, 0 newly installed, 0 to remove and 4 not upgraded.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' '192.168.56.70'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
Number of key(s) added: 1
Now try logging into the machine, with:   "ssh -o 'StrictHostKeyChecking=no' '192.168.56.77'"
and check to make sure that only the key(s) you wanted were added.


잘 넘어간 듯 보인다. 확인해보자.


root@s1:~# ls -a
.  .bash_history  .cache  .nano    _setting  .viminfo
..  .bashrc        my.sh  .profile  .ssh      xx.tar
root@s2:~/.ssh# vi authorized_keys
ssh-rsa  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrs6M3/80EYZ6qvoiPC/H/bIxsZJEqXdEKfy9sy+yCyEgFteidGXeq/4+8Tb0QMAJ+I8Ia6uEFk1hjPCEdnlwNAuIV9GQfi//kHJOTmlPdDoOEvd9w20dfjGvqBmB2nIIMuq+fNeU7GV6C3tGWNc9nTuH+DFZEqmcT1tpp9gxocnJ5Lo/4xvPkzjSSPC9W2H6BxhOkp8V4Tpj7oA8a3OhIUaIyyrMjcUkpXTrWffDDWqdpDU1yxCh2xhV+ddP/bPJEhu52cmWDXnn5m5+xB48NQAMNOfb/Go3bPPW2hLCMazAj7T+WHq3HbSAKE8U291DnkT2UuSCE3jOFzpQ9Lc9V root@s1


root@s1의 공개키가 잘 입력되었음을 알 수 있다.

이제 geth 환경을 한번에 구축해주는 스크립트를 짠 뒤, 추후 본 포스트에 업데이트 할 것이다.


지금부터는, 서브라임 텍스트로 원격으로 s1서버에 쉘스크립트 작업을 할 수 있는 환경을 구축하고, root 유저로 접속해서

blockchain이라는 유저를 생성하고 해당 유저에 go 설치 및 필요하다면 build-essential 등등 라이브러리도 세팅, geth 빌드와 blockchain 유저가 geth를 사용할 수 있도록 환경을 구축해보겠다.

  1. 서브라임텍스트(Sublime Text) 설치하기

sublime text 3 를 깔아서 써보자.

편집기 필요요소
코드하이라이팅
자동완성
오류캐치

등등이 가능하다.

이 서브라임 텍스트는 또한 패키지 라는 개념으로 여러 기능들을 확장할 수 있다.

패키지를 설치하는 것은 파이썬 코드로 먹이는 것인데, 패키지 컨트롤을 이용하면 쉽게 새로운 패키지를 추가할 수 있다.


이 페이지로 가서, 아래 텍스트를 서브라임텍스트의 화살표 부분 창에 복붙한다.

import urllib.request,os,hashlib; h = '6f4c264a24d933ce70df5dedcf1dcaee' + 'ebe013ee18cced0ef93d5f746d80ef60'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)



그러면 패키지 컨트롤 인스톨러가 설치된다. (이 창은 ctrl+1옆의 홑따옴표 누르면 켜진다)

다음은 command+shift+P (윈도우는 커맨드 대신 컨트롤) 을 눌러보자.



누르고, 이 화면에서 pci를 치고 엔터 한번 누른 다음 아래 패키지들을 설치하자.
(PCI를 치고 매번 엔터 쳐줘야 안의 놈들이 나온다)

Emmet
Text Pastry
SFTP
SublimeCodeIntel

다 설치했다. 이제 여기서 서버를 돌릴 때 s1과 s2의 root로 접속이 가능하도록 터미널에서 세팅을 해주자.

  1. 터미널에서 s1 가상 컴퓨터의 root 외부 접속 허용 세팅

다시 터미널 창으로 가서, s1과 s2의 루트 비밀번호를 설정해준다.

han@s1:~$ sudo su
root@s1:/home/han# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@s1:/home/han# exit
Exit
han@s1:~$ ssh s2
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.15.0-33-generic x86_64)
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
3 packages can be updated.
0 updates are security updates.
New release '18.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Last login: Wed Aug 29 10:18:51 2018 from 192.168.56.70
han@s2:~$ sudo su
sudo: unable to resolve host s2
root@s2:/home/han# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
root@s2:/home/han# exit
exit
han@s2:~$ exit
logout
Connection to s2 closed.
han@s1:~$ su
Password:
root@s1:/home/han# cd
root@s1:~# pwd
/root
root@s1:~# 
root@s1:~# vi /etc/ssh/sshd_config 



여기서 PermitRootLogin을 yes로 바꿔준다.

root@s1:~# service ssh restart

까지 입력해주면, 이제 외부 접속에 대한 것은 세팅이 되었다.

자, 이제 s1의 /root 폴더에 우리는 위치해있다.

다시 서브라임텍스트로 돌아가자.

  1. 서브라임텍스트(Sublime Text)로 html과 서버 구축해 s1의 root에 연결하기

서브라임 텍스트에서는 html 파일을 만들고 서버를 돌릴 수 있다.

현재 열린 파일을 hello.html로 저장하고, 아래와 같이 치고 탭을 누르면...!





이렇게 변한다. 이 것이 바로 젠코딩이다. 엄청 간편하지 않은가!

컨트롤 f 로 td를 찾고 findall을 누르면 아래처럼 멀티라인 편집도 가능하다.



이 상태에서 command shift P를 누르고 text Pastry의 여러가지 기능을 이용하면 아래와 같은 짓도 가능하다.



File - sftp - setup server 누르고 호스트와 호스트 유저, 포트와 패스워드, 리모트 패스(기본 접속 경로)를 입력해주자.



이제, file - stfp - browse server 에 들어가 s1을 눌러 파일 경로들이 나오면 잘 만들어진 것이다.

Folder action - new file - my.sh 를 만들어보자.



잘 만들어졌다.

터미널에서 확인해보자.

root@s1:~# ls

이제 우리는 sublime text에서 my.sh를 변경하면 바로 터미널에서 확인이 가능하다.


  1. Bash 스크립트 익숙해지기

자, my.sh를 하나의 스크립트로 만들어보자.

만들 스크립트의 내용은 아래와 같다.

 xx 폴더를 만들어 그 안에 a.txt 파일을 만들고, hello world라는 문장 넣은 다음 xx폴더를 xx.tar로 압축하고 xx폴더는 삭제

#!/bin/bash
mkdir xx
echo "hello world" >> xx/a.txt
tar -cf xx.tar xx
rm -rf xx

가 될 것이다.

실행해보자.

root@s1:~# ./my.sh
root@s1:~# ls
my.sh  xx.tar

스크립트의 결과로 xx.tar가 생긴 것을 볼 수 있다.

이번엔, 1부터 10까지 합을 출력하는 스크립트를 만들어보자.

#!/bin/bash
hap=0
#for i in 1 2 3 4 5 6 7 8 9 10:
#for i in 'seq 10';do
for (( i = 0; i < 10; i++ ));do
    hap=`expr $hap + $i`
done
echo "1부터 10까지의 합: "$hap
exit 0

For 문을 돌리는 방법은 위 3가지이다. 직접 입력해주던가, 시퀀스를 쓰던가, 범위를 지정해주던가.

여기서 주의해주어야 할 것은, for문 안의 hap 내용에는 1 옆의 홑따옴표가 사용되어야한다는 것이다. 안그러면 아래와 같은 에러 메시지를 볼 것이다.

root@s1:~# ./my.sh
1부터 10까지의 합: expr $hap + $i

1 옆의 홑따옴표를 사용하면 아래와 같이 잘 나온다.

root@s1:~# ./my.sh
1부터 10까지의 합: 45

이번엔, 구구단의 3단을 출력해보자.

#!/bin/bash
for (( i = 1; i < 10; i++ ));do
    val=`expr $i \* 3`
    echo 3 \# $i = $val
done
exit 0

실행해보면 아래와 같은 결과를 얻는다.

root@s1:~# ./my.sh
3 # 1 = 3
3 # 2 = 6
3 # 3 = 9
3 # 4 = 12
3 # 5 = 15
3 # 6 = 18
3 # 7 = 21
3 # 8 = 24
3 # 9 = 27
root@s1:~#

이번엔 사용자가 parameter를 입력해 만드는 구구단 스크립트를 짜보자.

#!/bin/bash
val=0
if [ "$1" = "" ]; then
    echo "no parameter"
else
    for (( i = 1; i < 10; i++ ));do
        val=`expr $1 \* $i`
        echo $1 \# $i = $val
    done
fi
exit 0

여기서 $1은 사용자가 입력하는 상수 파라미터를 뜻한다.

이제 실행해보자.

root@s1:~# ./my.sh 7
7 # 1 = 7
7 # 2 = 14
7 # 3 = 21
7 # 4 = 28
7 # 5 = 35
7 # 6 = 42
7 # 7 = 49
7 # 8 = 56
7 # 9 = 63

단, 어디 변수에 $ 표시를 빼먹으면 아래와 같은 메세지를 볼 수 있다.

root@s1:~# ./my.sh 7
expr: non-integer argument
7 # 1 =
expr: non-integer argument
7 # 2 =
expr: non-integer argument
7 # 3 =
expr: non-integer argument
7 # 4 =
expr: non-integer argument
7 # 5 =
expr: non-integer argument
7 # 6 =
expr: non-integer argument
7 # 7 =
expr: non-integer argument
7 # 8 =
expr: non-integer argument
7 # 9 =

오늘은 여러가지 쉘스크립트를 연습해보았다.


6ba9722900115eb3e82dc4241c7f7bc0_1518415633_3077.JPG

 

해당 키를 삭제한다.

6ba9722900115eb3e82dc4241c7f7bc0_1518415633_393.JPG

 

6ba9722900115eb3e82dc4241c7f7bc0_1518415731_4898.png

+ Recent posts