Bash 스크립트

운영체제로그/Linux 2011. 1. 20. 22:33
리눅스를 서버로 자바언어 기반의 웹서비스를 운영하려고 준비하다가,  로그를 
시간, 일일 단위로 수집하여 에러가 발생하면 메일로 전송해주는 기능을 작성해야할 일이 생겼다. 
스프링에서 지원해주는 스케줄링과 메일전송 기능을 사용할 수도 있지만, crontab과 몇 가지 리눅스 유틸리티를
사용해서도 쉽게 해결할 수 있는 일이다. 

일단 스크립트에 익숙지  않기 때문에   Bash 스크립트 구문을  간략히 정리해보고 원하는 기능을 구현해보자

사용자의 디폴트쉘은  /etc/password 파일에 사용자 엔트리에 기반하여 적용이 되며,  대부분 bash(/bin/bash)가 사용된다. 
bash 쉘은 시작시에 /etc/profile 파일을 읽어서 모든 사용자에 쉘환경에 적용을 한다.  사용자 홈디렉토리에 위치하고 있는
.bash_profile, .bash_login, .profile 파일은 현재 쉘환경만 적용이 된다. 쉘이 닫힐 때는 ~/.bash_logout 파일이  실행이 된다. 

1 스크립트 실행 
스크립트를 실행하기 위해서는, 파일에 실행권한을 부여해야 한다. 
$chmod u+x myscript.sh
bash 명령을 주어 명시적으로 실행하려면,  스크립트 파일의 가장 첫라인은 다음과 같이 시작해야 한다. 
#!/bin/bash

2 변수선언과 테스트문 
테스트문은 참과 거짓을 판별하는 표현식으로 대괄호[] 안에 표시를 한다.  변수를 선언하고 테스트문을 사용하는 예이다. 
MYSTRING=abc if [ $MYSTRING = abc ] ; thenecho “The variable is abc” if
위 예에서는 MYSTRING 이라는 변수를 선언하고 그 값이 "abc" 와 같은면 메시지를 출력하고 있다. 
다음은 테스트문에서 수를 비교하는 예이다. 
MYNUMBER=1 
if [ $MYNUMBER -eq 1 ] ; then
    echo “MYNUMBER equals 1”; 
fi 

if [ $MYNUMBER -lt 2 ] ; then 
    echo “MYNUMBER <2”; 
fi 

if [ $MYNUMBER -le 1 ] ; then 
    echo “MYNUMBER <=1”;
 fi 

if [ $MYNUMBER -gt 0 ] ; then 
    echo “MYNUMBER >0”; 
fi 

if [ $MYNUMBER -ge 1 ] ; then 
    echo “MYNUMBER >=1”; 
fi

각각 MYNUMBER 변수에 있는 값을 비교하여 메시지를 출력하고 있다. 테스문에서 사용한 기호는 각각 =, <, <=, >, >= 를 의미한다. 다음은 파일에 대한 테스문 예이다.
filename=”$HOME” 
if [ -e $filename ] ; then 
    echo “$filename exists”; 
fi

if [ -f “$filename” ] ; then
    echo “$filename is a regular file” 
elif [ -d “$filename” ] ; then	
    echo “$filename is a directory” 
else	
    echo “I have no idea what $filename is”
fi
위에서 사용한 테스트문 연산자에 대해서 알아보자 .

                      연산자   의미  연산자  의미
 -e(a) file 파일이 존재하는지 검사   expr1 -a expr2 and 
 -d file  파일이 디렉토리인지 검사  expr1 -o expr2  or
 -f file  파일이 일반파일인지 검사  file1 -nt file2  modification time is newer than
 -L(f) file 파일이 심볼릭 링크인지 검사   file1 -ot file2  modification time older than
 -n string 문자열길이가 0보다 큰지검사   file1 -ef file2 두 파일이 링크로 연결유무 
 -z string 문자열길이가 0인지 검사   var1 -ne(!=) var2  not equal
 -o file 파일을 소유하고 있는지검사   var1 -eq(=) var2  equal
 -r file 파일을 읽을 수 있는지 검사   var1 -ge var2  equal or greater than
 -w file  파일을 쓸 수 있는지 검사  var1 -gt var2  greater than
 - x file  파일을 쓸 수 있는지 검사  var1 -le var2 less than or equal 
 -s file  파일이 존재하고, 
0바이트보다 큰지 검사
var1 -lt var2   less than
   
 


3 case 문 (c언어의 switch 문)
case “$VAR” in	 
string1)		
    { action1 };; 
string2)		
    { action2 };;	
*)		
    { default action } ;; 
esac


4 for 문
for NUMBER in 0 1 2 3 4 5 6 7 8 9 do	echo The number is $NUMBER done
아래와 같이 backtick(`)으로 감싸 ls 명령을 수행한 결과에 대해서 반복을 할수도 있다. 
for FILE in `/bin/ls`; do
     echo $FILE; 
done


5 while문
변수를 카운트하여 루프를 도는 예이다. 
VAR=0 
while [ $VAR -lt 3 ]; do
    echo $VARVAR=$[$VAR+1]
Done


6 until 문
until 구문을 사용하여,  while 문과 동일한기능을 수행할 수 있다. 
VAR=0 until [ $VAR -eq 3 ]; do echo $VAR; VAR=$[$VAR+1]; done

[Ubuntu] NFS 사용하기

운영체제로그/Linux 2011. 1. 10. 00:05

NFS(Network File System) 은 원격호스트에 있는 파일시스템을 로컬 하드인 것처럼 사용할 수 있는 
선마이크로 시스템즈사에 의해 개발된 파일시스템이다.  지금과 같이 파일공유가 되지 않았던 예전에 많이 사용되었던
방식이라고 한다.  NFS는 서버 / 클라이언트 모델로 동작하는데, 파일소스를 제공하는 측이 서버가 되고,  파일소스를 이용하는 
측이 클라이언트가 된다.
우분투/데비안에서,  NSF 클라이언트로 동작하기 위해서는 nfs-common, portmap 패키지가 필요하며,  
서버로 동작하기 위해서는  nfs-common, portmap, nfs-kernel-server,  패키지가 필요하다. 이름대로 nfs-common 패키지는
서버와 클라이언트 에서 공통으로 사용하는 모듈로,  showmount, nfsstat 등의 유틸리티가 포함되어 있다.  
 


이제 NFS 를 설치해보자. 
 

1. 패키지 설치 (서버, 클라이언트 패키지 모두 설치)
# apt-get install nfs-kernel-server nfs-common portmap




2. /etc/exports 파일에 공유폴더 설정하기 (서버측 설정)
/folderToShare1 192.168.1.10(rw,no_root_squash,async)
/folderToShare2 192.168.1.1/24(rw,no_root_squash,async)

exports 설정파일은 <공유폴더 공유호스트1(옵션) 공유호스트2(옵션) ...> 와 같은 형태를 따른다. 
한줄에 여러 호스트를 지정할 수 있으며, 2번줄처럼 서브넷마스크를 적어주어 ip범위(1~255)를 지정해
줄 수도 있다. 참고로 맥에서 공유폴더를 마운트하기 위해서는 반드시 insecure 옵션을 명시해 주어야 한다. 




3. export 파일을 편집했다면 nfs 데몬을 재실행하여 변경사항을 적용해 준다 (서버측 설정)
# sudo /etc/init.d/nfs-kernel-server restart




4. 클라이언트에서 원격호스트 폴더를 마운트하여 사용한다. (클라이언트측 설정)
# mkdir ~/mymount

# cd ~

# sudo mount servername:/folderToShare1 ~/mymount 
서버의 exports 파일에 명시된 호스트라면, mymount 디렉토리에  /folderToShare1 서브디렉토리들이 마운트되어
이후에는 로컬 디스크처럼 사용할 수 있다. 




5. 마운트를 해제하기 위해서는 아래와 같이 한다 
#umount ~/mymount 




OAuth의 세부사항

네트워크로그 2011. 1. 1. 03:05




지난 포스팅에 이어 OAuth의 세부사항에 대해 알아보자

① Request Token 요청 / ③ Access Token 요청 / ④ Protected Resources 요청 단계에서 적절한 oauth 파라미터를 함께 전달해주어야 
하는데 이 파라미터들에 대해서 알아보자. Consumer는 ServiceProvider 에게 3가지 방법 중 하나를  통해 파라미터를 전달할 수 있다. 
1) HTTP 헤더에 Authorization 헤더를 통해 전달한다. 
2) HTTP 헤더의 POST request body를 통해 전달한다. (이때 Content-Type 헤더는 application/x-www-form-urlencoded로 설정함)
3) URL의 쿼리 파트를 통해 전달한다. 

어느 방법을 선택해도 되지만, 이 포스팅에서는 첫번째 방법을 설명하겠다.  전체적인 흐름을 나타낸 그림은 다음과 같다. 



oauth 파라미터
oauth  파라미터는 OAuth 스펙에서 요구하는 "oauth_ " 접두어를 갖는 파라미터를 의미한다. oauth 파라미터의 종류와 그 의미는 
다음과 같다. 

  oauth_version  OAuth 프로토콜의 버전으로 1.0으로 설정하며, 선택적인
 파라미터 값이다
 oauth_consumer_key   ServiceProvider 에서 제공하는 Consumer 를 고유하게 식별하기 위한 값
 oauth_token   request token 값으로 Request token 요청시에는 사용되지 않으며,
  Access token 요청과 자원조회시에는 사용된다. 
 oauth_timestamp   GMT 1970년 1월 1일 00:00:00 이후 현재까지의 흐른 초로,  밀리초가 아닌 초 단위 임에 주의하자 
 oauth_nonce  reply attack 을 예방하기 위해,  동일한 timestamp 를 갖는 요청마다 유일한  랜덤값이다. 
 oauth_signature_method  oauth 파라미터 값들이 도중에 변경되지 않았음을 보장하기 위해 사용하는 해시 알고리즘의 종류로, HAC-SHA1,  RSA-SHA1
등이 있다. 이 포스팅에서는  HAC-SHA1 를 사용한다.  
 oauth_signature  HMAC-SHA1 를 사용하여 생성한 알고리즘의 결과값이다.
 이 알고리즘 적용에 필요한 키와 데이터에 대해서는 아래에서 자세히 다루겠다. 
 oauth_callback  Authorize URL 에 접속하여 사용자의 허용을 받고 리다이렉트
시킬 URL 이다. Consumer가 웹서비스가 아닌 애플리케이션이면
 "oob"  로 설정해야 한다. (oob는 out of band의 약자이다.)
 oauth_verifier  사용자 허용을 통해 응답받은 값으로, Access token 요청시에만 설정한다.  

각 단계별로 필요한 파라미터들을 요약한 결과는 다음과 같다. 
Request token URL  요청: oauth_consumer_key,  oauth_callback, oauth_timestamp, oauth_nonce, oauth_signature_method, oauth_signature
                                            oauth_version
Access token  URL  요청: oauth_consumer_key,  oauth_callback, oauth_timestamp, oauth_nonce, oauth_signature_method, oauth_signature,                                                oauth_version, oauth_token, oauth_verifier
Protected Resources 요청: oauth_consumer_key,  oauth_callback, oauth_timestamp, oauth_nonce, oauth_signature_method, oauth_signature,                                                oauth_version, oauth_token


oauth_signature 생성하기
HAC-SHA1 해시알고리즘을 사용하여 시그너처를 생성하는 방법을 알아보자.  각 파라미터들은 percent 인코딩 또는 Base64 인코딩을 하기전에 반드시 UTF-8 로 인코딩해야함을 주의하자.

이 알고리즘은 키를 바탕으로 데이터에 대한 해시 값을 생성하게 되는데,  data는 Signature Base String 이 되며,  key 는 
Consumer Secret 와 Token Secret 를 & 문자로 연결한 값이 된다. 

HMAC-SHA1의 데이터 생성 ( Signature Base String 생성)
생성 절차는 좀 까다로운데 절차는 다음과 같다. 
① oauth_signature 파라미터를 제외한 oauth 파라미터들의 키와 값을 각각 percent 인코딩을 하고 =문자로 연결한다. 
     (HTTP request의  post body값이 존재하면 이 값도 동일한 연산을 수행한다)
② oauth 파라미터( 키=값) 쌍을 키의 알파벳순으로 정렬한 후  &문자로 연결하여 정규화된 문자열을 생성한다 
    (키가 동일하면, 값의 알파벳순으로 정렬함)
③  Request URL을 percent 인코딩한다. 
④ HTTP request method(대문자) 와 인코딩된  Request URL, 그리고 정규화된 문자열을 & 문자로 연결하고, percent  인코딩하여
    Signature Base String을 생성한다.   
 

HMAC-SHA1의 키 생성 
① consumer secret를 percent 인코딩한다 
② token_secret를 percent 인코딩한다.  (token_secret 은 Request Token 요청시에는 공백값이며, Access Token 요청시에는 
     Request token의 secret이며,  자원 요청시에는 Access Token의 secret 이 된다. )
③ 인코딩된 consumer secret 값과 token secret 값을  & 문자로 연결하여 최종 데이터를 생성한다. 

Base64 인코딩으로 바이너리 값을 아스키 값으로 변경 
위에서 생성한 키와 데이터를 바탕으로 HMAC-SHA1 알고리즘을 적용하면, signature 의 바이너리 값을 얻을 수 있다.
이 데이터에 Base64 인코딩을 적용하여, 아스키코드값으로 변경하고, 다시 percent 인코딩을 적용하여 최종 signature 값을 
생성한다. 

지금까지 생성한 oauth 파라미터드를 HTTP  request의 헤더에 설정하고, 요청만 하면된다. 하지만 아직 한단계가 더 남아있다. 
HTTP  request 의 Authorization 헤더값를 생성하는 것이다. 

Authorization  헤더값 생성
 "OAuth  " (공백이 있다는 것에 주의) 문자열과 모든 oauth 파라미터의 키와 쌍따옴표로 감싼 값쌍을 =문자료 연결하고 다시 각각을  ,(쉼표)문자로 연결한다 
최종헤더 값은 다음과 같은 형태일 것이다. 
OAuth oauth_callback="oob", oauth_timestamp="13882494", ......


이제는 거의 마지막 과정까지 왔다. 각각 생성한 oauth 파라미터의 키와 값, Authorization 헤더의 키와 값을 HTTP 헤더에 설정하고, 
http 요청을 하면 된다.   HTTP 헤더와 HMAC-SHA1의 키와 데이터를 표현한 그림은 다음과 같다. 

HMAC-SHA1 알고리즘 키와 데이터에 인코딩 적용여부는 그림에 표현하지 않았다.