Showing posts with label shell script. Show all posts
Showing posts with label shell script. Show all posts

Saturday, March 16, 2019

Bash 쉘 프로그래밍 - 3. Bash 쉘 환경 #2. 변수 정의 및 호출

■ 변수란? (Variable)

변수는 변할 수 있는 값(수, 문자, 문자열)을 대표하는 문자입니다. 일반적인 컴퓨터 언어에서는 자료형(데이터 형식)에 따른 변수 선언 (정수, 실수, 문자열 같은)을 하는데 쉘에서 자료형을 잘 설정하지 않습니다. 다른 언어들도 다 그러하지만 쉘도 예약 변수와 일반 변수가 있으며 일반 변수에는 지역 변수와 환경 변수가 있습니다. 보통 변수 이름은 아래와 같이 대문자를 사용합니다.

[root@shell01 ~]# A=1

현재의 쉘(Shell)에서 A는 변수이며 변수에 1이란 값이 정의되었습니다. 변수의 값을 호출하기 위해 변수 앞에 $기호를 입력하면 됩니다

[root@shell01 ~]# echo $A
1

또는 아래와 같이 변수의 값을 판단하는 조건문에 아래와 같이 사용할 수도 있습니다.

[root@shell01 ~]# if [ $A -eq 1 ]; then echo "A Value is $A"; else "A Value is not 1"; fi
A Value is 1

■ 변수 정의 및 호출

변수를 정의하는 방법은 간단하다. '변수 이름=값' 이렇게 정의하면 되며 값을 숫자로 넣으면 숫자형, 문자로 넣으면 문자형이 된다.

[root@shell01 ~]# A=1
[root@shell01 ~]# NAME=Sunguru
[root@shell01 ~]# JOB='IT Manager'
[root@shell01 ~]# DATE=`date "+%Y-%m-%d %H:%M"`

그리고 아래와 같이 echo 명령을 통해 변수의 값을 호출할 수 있습니다.

[root@shell01 ~]# echo "TIME : $DATE
> Hello ${NAME}, ${A}.$JOB"
TIME : 2017-02-27 09:25
Hello Sunguru, 1.IT Manager

변수값을 호출할 때 변수 이름 뒤에 바로 뒤따르는 문자 또는 문자열이 있다면 변수 이름과 구분 짓기 위해 중괄호 {}를 사용할 수 있습니다. 변수값을 꼭 미리 정의하는 것이 아닌 명령의 결과 값으로 또는 사용자 입력을 통해 받을 수 있습니다. 위에서 date 명령의 결과값을 DATE 변수값으로 정의하였습니다.

사용자로부터 값을 받기 위해 read이라는 쉘의 내장 명령을 사용할 수 있습니다. read 명령 다음에는 사용자로부터 받은 값을 저장하기 위한 변수 이름을 정의합니다.

[root@shell01 ~]# read NAME
Edward
[root@shell01 ~]# echo $NAME
Edward

이렇게 하면 알아보기 힘들기 때문에 사용자에게 값을 입력 유도하는 문장을 출력한 후 값을 받기 위해 아래와 같이 쉘 스크립트 파일을 만들 수 있습니다.

[root@shell01 ~]# vi scripts/name.sh

#!/bin/bash
echo -n "Enter your name : "
read NAME
echo 
echo "Your name is $NAME."

그리고 스크립트 파일을 실행하기 위해 아래와 같은 명령을 사용할 수 있습니다. 실행 권한을 부여한 후 실행하여도 되고 bash 쉘을 실행하여 파일을 읽어들여 실행하게 만들 수도 있습니다.

[root@shell01 ~]# bash scripts/name.sh
Enter your name : Gilbert

Your name is Gilbert.

■ 쉘 스크립트 파일 실행

쉘과 쉘 스크립트 파일의 차이점은 앞에서 언급하였습니다. 쉘 스크립트 파일을 실행하는 방법은 어떠한 것이 있을까요? 쉘 스크립트 파일을 만들면 일반적으로 실행 권한을 부여합니다. 다른 사용자도 사용할 수 있도록 할지 자신만 사용할지를 잘 결정하여 권한을 부여하는 것이죠. 그리고 파일을 실행합니다.

[root@shell01 ~]# chmod +x test.sh
[root@shell01 ~]# chmod u+x test.sh
[root@shell01 ~]# chmod  
[root@shell01 ~]# ./test.sh

이때 ./의 뜻은 '현재 디렉터리 밑에'라고 보시면 됩니다. 또는 아래와 같이 bash 명령을 실행하여 인자 값으로 쉘 스크립트 파일명을 줘도 실행됩니다. 보통은 디버그를 하기 위해 -x 옵션을 줘서 실행하죠.

[root@shell01 ~]# bash test.sh
[root@shell01 ~]# bash -x test.sh

또는 반복적으로 실행하는 명령을 특정 디렉터리에 보관하고 있다면 .bash_profile 초기화 파일에 PATH 변수에 경로를 설정하고 쉘 스크립트 파일 이름으로 실행할 수 있습니다. 유닉스나 리눅스는 확장자에 대한 의미를 크게 두지 않습니다.

[root@shell01 ~]# bash test.sh

다음 게시물에서 지역변수와 환경변수에 대해 알아보도록 하겠습니다.



Bash 쉘 프로그래밍 - 3. Bash 쉘 환경 #1. 쉘의 초기화 파일

■ Bash (Bourne-again shell) 쉘

오래전 유닉스 시절부터 사용되어 온 bourne 쉘을 대처하기 위해 그리고 GNU 프로젝트를 위해 1988년 1월 10일 Brian Fox 가 bash 쉘을 코딩했습니다.. 그리고 본 쉘 (Bourne)의 문법은 거의 모두 호환되어 본 쉘에 익숙한 엔지니어들도 배시 쉘을 거부감 없이 그대로 사용할 수 있습니다. Bash 쉘은 리눅스뿐만 아니라 Mac OS X, Unix, Novel Netware 등에 포팅되어 광범위하게 사용되고 있습니다.

배시 쉘 (Bash Shell)이 가지고 있는 대표적인 특징은 명령 히스토리(과거 명령 불러오기. 화살표 아래, 위 키 사용), 파일 이름 자동 완성 기능(Tab 키를 사용), 디렉터리 스택 등이 있습니다. 이 중에서 명령 히스토리 기능과 파일 이름 자동 완성 기능은 리눅스와 유닉스 엔지니어들이 매우 좋아하는 기능입니다. 배시 쉘(Bash Shell)은 리눅스의 기본 쉘(Default Shell)입니다.

■ 배시(Bash shell) 쉘 초기화 파일

사용자 로그인 후 쉘 생성시 쉘의 환경을 설정하는 파일을 쉘 초기화 파일(Shell Initialization Files)이라 합니다.

적용 범위
내 용
System-wide
 이 파일은 시스템 관리자가 관리하는 파일이다. bash 쉘 사용자 전체에게 영향을 주기 위해 사용한다.

  /etc/profile
  /etc/bashrc
User Configuration
 이 파일은 시스템 사용자가 관리하는 파일이다. 사용자에 한정되어 영향을 주기 위해 사용한다.

  $HOME/.bash_profile
  $HOME/.bashrc
  $HOME/.bash_logout

1). /etc/profile

사용자 로그인 후 배시 쉘이 실행될 때 bash 쉘에 의해 읽어지고 실행되는 파일입니다. 배시 쉘 사용자 전체에게 영향을 주기 위해 사용되는 파일이기 때문에 시스템 관리자에 의해 관리됩니다. 이 파일에는 배시 쉘의 예약된 변수 또는 사용자에게 적용되었으면 하는 일반 변수와 umask 값, 함수 및 쉘의 문법 등이 정의되어 있습니다. 이 파일의 내용에서 줄의 첫 문자 #은 주석을 의미합니다.

2). /etc/bashrc

사용자 로그인 후 배시 쉘이 실행될 때 배시 쉘에 의해 읽어지고 실행되는 파일입니다. bash 사용자 전체에게 영향을 주기 위해 사용되는 파일이기 때문에 시스템 관리자에 의해 관리됩니다. 환경 변수 같은 경우 하위 프로세스(Sub Process)에 상속이 되지만 별칭(Alias) 경우 상속이 되지 않습니다. 그래서 별칭(Alias)를 이 파일에 정의를 해놓는다. 쉘의 하위 쉘 프로세스가 열릴 때 자동으로 이 파일을 다시 읽어 들입니다.. 이 파일의 내용에서 줄의 첫  문자 #은 주석을 의미합니다.

3). $HOME/.bash_profile ( 또는 ~/.bash_profile)

사용자 로그인 후 배시 쉘이 실행될 때 배시 쉘에 의해 읽어지고 실행되는 파일입니다. 배시 쉘을 사용하는 사용자에 한정되어 영향을 주는 파일이며 사용자의 홈 디렉터리에 존재하는 파일입니다. 이 파일에는 bash 쉘의 예약된 변수 또는 사용자에게 적용되었으면 하는 일반 변수와 umask 값, 함수 및 쉘의 문법 등이 정의되어 있습니다. 이 파일의 내용에서 줄의 첫문자 #은 주석을 의미합니다.

4). $HOME/.bashrc ( 또는 ~/.bashrc)

사용자 로그인 후 배시 쉘이 실행될 때 배시 쉘에 의해 읽어지고 실행되는 파일입니다. bash 쉘을 사용하는 사용자에 한정되어 영향을 주는 파일이며 사용자의 홈 디렉터리에 존재하는 파일입니다. 환경 변수 같은 경우 하위 프로세스(Sub Process)에 상속이 되지만 별칭(Alias) 경우 상속이 되지 않습니다. 그래서 별칭(Alias)를 이 파일에 정의를 해놓는다. 쉘의 하위 쉘 프로세스가 열릴 때 자동으로 이 파일을 다시 읽어 들입니다. 이 파일의 내용에서 줄의 첫 문자 #은 주석을 의미한다.

5). $HOME/.bash_logout ( 또는 ~/.bash_logout )

로그아웃 진행 전 배시 쉘에 의해 읽어지고 실행되는 파일입니다.

6). bash 쉘 사용자 로그인의 예

먼저 아래와 같은 파일을 vi 편집기를 사용하여 echo 명령을 삽입하였습니다.. 이를 통해 bash 쉘 사용자 로그인 시 그리고 하위 쉘(Sub Shell) 생성 시 어떠한 파일이 읽어지는지를 알 수 있습니다.


아래는 '# su - user1' 명령을 실행하여 user1 사용자로 전환하였습니다. 그리고 결과 내용을 자세히 보자. 어떠한 파일이 먼저 읽어졌는지 알 수 있습니다. 실제 이러한 순서를 더 자세히 알기 위해서는 /etc/profile, /etc/bashrc, /etc/.bash_profile, /etc/.bashrc 파일 내용을 자세히 살펴볼 필요가 있습니다. 하지만 이 게시물에서는 이 정도만 다룰 것입니다. 배시 명령을 통해 하위 bash 쉘을 실행하였고 부모 bash 쉘과 자식(하위 또는 sub) bash 쉘이 서로 다른 PID를 가지는 것을 확인하기 위해 'echo $$' 명령을 실행했습니다. 이 정도면 쉘 초기화 파일이 어떻게 동작하는지 알 수 있을 것이라 생각됩니다.

[root@centos01 ~]# su - user1
this file is /etc/profile
this file is /etc/bashrc
this file is /home/user1/.bashrc
this file is /home/user1/.bash_profile

[user1@centos01 ~]$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
user1    18238 18237  0 14:31 pts/0    00:00:00 -bash
user1    18281 18238  0 14:32 pts/0    00:00:00 ps -f

[user1@centos01 ~]$ bash
this file is /etc/bashrc
this file is /home/user1/.bashrc

[user1@centos01 ~]$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
user1    18238 18237  0 14:31 pts/0    00:00:00 -bash
user1    18282 18238  0 14:32 pts/0    00:00:00 bash
user1    18324 18282  0 14:32 pts/0    00:00:00 ps -f

[user1@centos01 ~]$ echo $$
18282



Thursday, March 14, 2019

Bash 쉘 프로그래밍 - 2. 쉘 스크립트(Shell Script)의 구조 #2 .새로운 디스크 스캔 예제

안녕하세요. 썬구루입니다.

쉘 프로그래밍(Shell Programming)에 흥미를 가지기 위해 간단한 스크립트를 만들어 보도록 하겠습니다. 리눅스 서버 시스템을 관리하다 보면 디스크를 추가해야 하는 경우가 있습니다. 서버 운영 시 디스크 추가가 가능하기 때문에 서버의 디스크 슬롯에 디스크를 장착하면 하드웨어적인 인식이 됩니다. 하지만 운영체제가 이를 사용하기 위해 디바이스 파일을 생성해줘야 하기 때문에 디스크 추가 후 디스크를 확인하면 바로 보이진 않죠. 윈도 서버 같은 경우 바로 보이지만요. 리눅스 운영체제에서 새 디스크를 인식시키기 위해 디스크 컨트롤러 scan 파일에 와일드 문자를 전달하면 관련 디바이스 파일이 생성되며 사용할 수 있게 됩니다. 디스크 추가를 위해 시스템 리부팅은 필요 없습니다. 테스트를 위해 VMware Workstation 기반에 설치된 리눅스를 사용하도록 하겠습니다. 일단 아래와 같이 디스크 컨트롤러 정보를 확인합니다.

[root@shell01 ~]# lspci | grep -i controller

00:0f.0 VGA compatible controller: VMware SVGA II Adapter
00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)
02:00.0 Ethernet controller: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) (rev 01)

SCSI Host를 재스캔(Rescan)하기 위해 사용되는 파일을 /sys/devices 디렉토리에서 검색합니다.

[root@shell01 ~]# find /sys/devices -name scan | grep 10.0

/sys/devices/pci0000:00/0000:00:10.0/host0/scsi_host/host0/scan

/sys/devices/pci0000:00/0000:00:10.0/host0/scsi_host/host0/scan 파일이 LSI Logic SCSI storage controller와 관련되어 있다는 것을 딱 봐도 아시겠죠. 이 파일에 와일드카드 문자를 전달하면 해당 컨트롤러에 연결된 디바이스들을 재스캔하게 됩니다.

[root@shell01 ~]# echo "- - -" > /sys/devices/pci0000:00/0000:00:10.0/host0/scsi_host/host0/scan

위와 같이 명령을 실행하면 새 디스크를 재스캔하게 됩니다. - 기호는 와일드카드 문자로 사용되며 첫 번째는 채널 (Channel), 두 번째는 SCSI Target ID, 세 번째는 LUN을 나타냅니다. 이것을 매번 하려면 귀찮죠.

실무 현장에서는 서버에 디스크 추가가 자주 일어나지 않습니다. 저희는 테스트를 위해 매번 가상머신에 디스크를 붙이는 작업하기 때문에 파일을 찾아 명령을 입력하기 귀찮기 때문에 그냥 쉘 스크립트 파일을 만들어 스크립트 파일을 실행하면 새로운 디스크가 바로 인식되도록 만들어 보겠습니다.

아래와 같이 find 명령을 사용하여 diskscan이라는 명령이 없는 것을 확인하고 root 사용자의 홈 디렉터리에 diskscan 파일을 만들어 실행 권한을 부여합니다.

[root@shell01 ~]# pwd

/root

[root@shell01 ~]# mkdir bin
[root@shell01 ~]# vi bin/diskscan.sh

#!/bin/bash
#
# Scan new disk for Linux based on VMware Workstation
# created by sunguru
# blog : http://sunguru-infra.blogspot.com
#
#Scan new disk
for y in `lspci | grep 'LSI Logic' | awk '{print $1}'`
do
FNAME=`find /sys/devices -name scan | grep $y`
echo '- - -' | sudo tee $FNAME 2>&1 > /dev/null
done
# Print HDD info
echo
lsblk | grep disk

[root@shell01 ~]# chmod 700 scripts/diskscan.sh

자 그럼.. 디스크를 추가한 후 diskscan.sh 쉘 스크립트 파일을 실행해보죠. 아래와 같이 lsblk 명령을 실행한 후 현재의 디스크 정보를 확인합니다. 그런 다음 가상머신에 10GB 디스크를 추가한 후 diskscan 쉘 스크립트 파일을 실행시킵니다. 그리고 lsblk 명령을 사용하여 다시 디스크 정보를 확인하면 sdb라는 10GB 디스크가 추가 인식된 것을 확인할 수 있습니다.

[root@shell01 ~]# lsblk | grep disk

fd0           2:0    1    4K  0 disk 
sda           8:0    0   10G  0 disk 

[root@shell01 ~]# diskscan.sh
[root@shell01 ~]# lsblk | grep disk

fd0           2:0    1    4K  0 disk 
sda           8:0    0   10G  0 disk 
sdb           8:16   0   10G  0 disk 

Wednesday, March 13, 2019

Bash 쉘 프로그래밍 - 2. 쉘 스크립트(Shell Script)의 구조 #1 .구조

안녕하세요. 썬구루입니다. 이 게시물에서 쉘 스크립트(Shell Script)의 구조(Structure)에 대해 알아보도록 하겠습니다.​

■ 쉘 스크립트 (Shell Script) 구조

쉘 스크립트 파일 내용은 기본적으로 아래와 같은 구조를 가집니다.

#!인터프리터(Interpreter)
#
# 주석(Comment)
#

함수명() {
  명령
  ...
}

명령1... (Command)
명령2...
명령3...

흐름제어 (Flow Control)

# 주석

함수호출

쉘 스크립트에서 주석 기호는 # 입니다. 한 줄 주석을 의미하며 # 기호 뒤에 따라오는 내용은 주석으로 처리합니다. 아래 내용을 쉘 스크립트 파일에 넣어 두면 # 기호는 주석이기 때문에 # 앞에 있는 명령만 쉘(Shell)에 의해 처리됩니다.

xfsdump -L "" -M "" -l 0 -f  /backup/boot_xfsdump_20170221.dmp /boot  # boot 파일시스템 백업

■ 첫 줄 #! (Shebang) 의미

하지만 첫 줄의 의미는 다릅니다. 첫 줄의 #! 를 Shebang 이라 하는데... 발음에 조심하셔야 할 듯.. 시방, 쉬방, 씨뱅 아님... 셔뱅이라고 읽는데 그 뒤에 스크립트를 처리할 인터프리터를 정의할 수 있습니다.

#!/bin/sh       <= 스크립트 내용을 본 쉘 ( Bourne Shell )로 처리
#!/bin/csh      <= 스크립트 내용을 씨 쉘 ( C Shell )로 처리
#!/bin/ksh      <= 스크립트 내용을 콘 쉘 ( Korn Shell )로 처리
#!/bin/bash     <= 스크립트 내용을 배시 쉘 ( Bash Shell )로 처리
#!/usr/bin/perl <= 스크립트 내용을 펄 ( Perl )로 처리
#!/usr/bin/python <= 스크립트 내용을 파이썬 ( Python )으로 처리

펄 ( Perl ) 로 처리하라고 하면 스크립트 내용이 펄 언어로 되어 있을 것이고 파이썬 ( Python ) 으로 처리하라고 하면 스크립트 내용은 파이썬 언어로 되어 있습니다. 저희는 당연 #!/bin/bash 를 사용할 것이죠.

■ # 주석 (Comments) 사용법

# 기호 주석 사용법은 초반에 쉘 스크립트의 목적와 쉘 스크립트 개발자 정보를 넣고 중간 중간에 기능에 대한 설명을 넣습니다. 예를 들면 아래와 같습니다.

#!/bin/bash
#
# 사용자로 부터 나이 입력을 받아 성인/미성년자 판단하는 스크립트
#
# 작성자 : 썬구루
# Blog : http://sunguru-infra.blogspot.com
#

# 사용자로 부터 나이 입력 받기

echo -n "How old are you : "
read AGE

# 입력 받은 나이에 대한 결과 처리

if [ $AGE -gt 18 ]; then
 echo "나이 $AGE.  성인입니다."
else
 echo "나이 $AGE. 미성년자입니다."
fi

중간 중간에 주석을 넣는 이유는 누가 보더라도 쉽게 이해하도록 만들기 위함입니다. 자기 자신에게 조차도요. 처음에는 한껏 필 받아서 열심히 짜고 만든 쉘 스크립트 파일이 잘 동작되는 것을 확인했는데 보름정도 있다가 쉘 소스 코드 ( Shell Source Code )를 보면 어떻게 코딩 ( Coding ) 했는지 자신이 만든 것이 맞는지 고개를 갸우뚱 하는 경우가 있습니다.

주석 기호를 사용하여 설명문을 넣어 그런 일이 발생하지 않도록 사전에 방지하는 효과도 있습니다.

■ 스크립트 내에 함수와 흐름제어를 꼭 사용해야 하나요?

쉘 프로그래밍 ( Shell Programming )을 매우 어렵게 생각하는 경우가 있는데 단순히 스크립트 파일 내용에 한 줄만 들어가도 됩니다. 함수, 흐름제어, 변수 선언 같은 것을 꼭 사용하지 않아도 반복적으로 실행하는 여러 개의 명령이 있다면 스크립트 내용에 사용하는 명령만 나열하여도 무방합니다.

#!/bin/bash
#
# /boot XFS 파일시스템 백업
#

xfsdump -L "" -M "" -l 0 -f  /backup/boot_xfsdump_`date +%Y%m%d`.dmp /boot  # boot 파일시스템 백업

위 내용처럼 /boot 파일시스템 백업을 위한 명령 한 줄만 적어도 쉘 프로그래밍을 한 것이죠. 쉘 프로그래밍에 대해 어렵다거나 너무 거창하게 생각 안 하셔도 됩니다.

■ 쉘 프로그램(Shell Program)을 잘 만드려면 어떻게 해야 하나요?

쉘 프로그램을 만드는 이유는 리눅스 또는 유닉스 시스템 관리를 편하게 하기 위함입니다. 하나의 작업을 위해 20개의 명령을 쳐야한다면 매번 20개의 명령을 치는 것이 아닌 쉘 스크립트 파일 내에 20개의 명령을 입력하고 작업이 있을 때마다 쉘 스크립트 파일을 한 번 실행 시키는 것이죠. 그럼 매번 20개의 명령의 실행할 필요없이 하나의 쉘 스크립트 파일을 한 번만 실행하면 되니까 작업의 효율성이 높아지는 것입니다.

그래서 쉘 프로그램을 잘 만들기 위해선 리눅스 또는 유닉스 명령을 많이 알고 있는 것이 중요합니다. 단순히 1부터 100까지의 합을 구하기 위해 쉘 프로그래밍을 하는 것은 아니거든요. 일주일에 한번씩 실행해야 하는 10개의 명령이 있다면 쉘 스크립트 파일을 만들고 cron으로 스케줄링을 하는 것이죠.

쉘 프로그래밍은 리눅스, 유닉스 관리자 또는 엔지니어에게는 꼭 필요한 기술입니다. 손 발의 수고를 덜기 위해서요. ^^