1.1. 개요
- 쉘과 파일을 이용하여 간단한 전화번호부 디비를 구축한다.
1.2. 틀 잡기
- 데이터의 입력, 삭제, 수정, 검색, 출력, 종료를 위한 사용자 입력을 받아들이는 틀을 만든다.
#! /bin/sh
DBASE="$HOME/phonebook.db"
while :
do
echo -n "전화번호부
a : 입력
d : 삭제
e : 수정
s : 검색
v : 출력
[enter] : 종료
원하시는 작업을 선택해 주십시오 ?(a, d, e, s, v, [enter]) : "
read RSP
case $RSP in
"") exit 0 ;;
a|A)
echo "입력"
;;
d|D)
echo "삭제"
;;
e|E)
echo "수정"
;;
s|S)
echo "검색"
;;
v|V)
echo "출력"
;;
*)
echo "명령어가 틀렸습니다. 다시 입력해 주세요."
;;
esac
done
1.2.1. 데이터 입력 하기
- 전화번호부에 저장할 이름, 직업, 전화번호를 입력 받는다.
- 이름이 없는경우(이름이 키값이 된다.) 해당 작업을 반복한다.
- 입력받은 내용은 echo "$NAME $OCCU $NUM" 의 형식으로 DB파일에 redirect한다.
- 전달한 내용은 sort -o 를 실행하여 소팅 결과를 동일한 파일에 다시 저장하게 하고 있다.
a|A)
echo -n "=============== [ 입력 ] ====================="
echo -n ""
echo -n "이름 = "
read NAME
if [ "$NAME" = "" ]
then
continue
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo -n ""
echo -n "=============================================="
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $DBASE
# 소팅 결과를 동일한 파일에 적용한다.
sort -o $DBASE $DBASE
;;
1.2.2. 데이터 삭제하기
- 데이터 삭제는 만들어진 데이터 베이스 파일에서, 삭제할 이름을 제외한 내용을 새로운 파일에 저장하고 새로운 파일의 이름을 원본 이름으로 변경한다.
d|D)
echo "=============== [ 삭제 ] ====================="
echo -n ""
echo -n "삭제할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
echo -n "이름은 키값이므로 반드시 입력하셔야 합니다."
echo -n ""
continue
fi
# 삭제할 이름을 이용하여 데이터베이스 파일에서 이름을 제외한 내용을 검색하고 새로운 파일에 만든다.
grep -v "$NAME" $DBASE > $DBASE.new
# 새로 만든 파일을 DBSE파일로 변경한다.
mv $DBASE.new $DBASE
echo ""
echo "=============================================="
;;
1.2.3. 검색하기
- 검색된 이름을 통해서 데이터베이스 파일내에 존재하는 이름을 가져온다.
- 검색은 grep -i 를 이용하여 대소문자 구분 없이 검색하게 하였다.
s|S)
echo -n "검색할 이름 : "
read NAME
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE
echo "-----------------------------------"
echo -n " 엔터키를 누르세요"
read RSP
;;
1.2.4. 데이터 출력하기
- more명령어를 사용하여 파일 내에 존재하는 모든 전화번호 내용을 출력한다.
v|V)
echo " 전화번호부 "
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
more $DBASE
echo "-----------------------------------"
echo -n "엔터를 누르시오"
read RSP
;;
1.2.5. 전체 소스
#! /bin/sh
clear
DBASE="$HOME/shell/data/phonebook.db"
while :
do
echo -n "전화번호부
a : 입력
d : 삭제
e : 수정
s : 검색
v : 출력
[enter] : 종료
원하시는 작업을 선택해 주십시오 ?(a, d, e, s, v, [enter]) : "
read RSP
case $RSP in
"") exit 0 ;;
a|A)
echo "=============== [ 입력 ] ====================="
echo -n ""
echo -n "이름 = "
read NAME
if [ "$NAME" = "" ]
then
echo -n "이름은 키값이므로 반드시 입력하셔야 합니다."
echo -n ""
continue
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo ""
echo "=============================================="
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $DBASE
# 소팅 결과를 동일한 파일에 적용한다.
sort -o $DBASE $DBASE
;;
d|D)
echo "=============== [ 삭제 ] ====================="
echo -n ""
echo -n "삭제할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
echo -n "이름은 키값이므로 반드시 입력하셔야 합니다."
echo -n ""
continue
fi
# 삭제할 이름을 이용하여 데이터베이스 파일에서 이름을 제외한 내용을 검색하고 새로운 파일에 만든다.
grep -v "$NAME" $DBASE > $DBASE.new
# 새로 만든 파일을 DBSE파일로 변경한다.
mv $DBASE.new $DBASE
echo ""
echo "=============================================="
;;
e|E)
vi $DBASE
;;
s|S)
echo -n "검색할 이름 : "
read NAME
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE
echo "-----------------------------------"
echo -n " 엔터키를 누르세요"
read RSP
;;
v|V)
echo " 전화번호부 "
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
more $DBASE
echo "-----------------------------------"
echo -n "엔터를 누르시오"
read RSP
;;
*)
echo "명령어가 틀렸습니다. 다시 입력해 주세요."
;;
esac
done
1.3. Version UP 1
- 기본틀 에서 사용상에 문제는 없으나 좀더 사용자가 쉽게 사용할 수 있도록 만들도록 한다.
1.3.1. 데이터 수정 보완하기
- 데이터 수정에서 vi를 사용하도록 하고 있는데 이 부분을 좀더 사용자입장에서 변경한다.
- 수정할 이름을 입력받고
- 수정할 직업, 전화번호를 이용하여 다시 저장하도록 한다.
- 사용자의 입력을 받았으면 삭제를 우선 수행한다.
- 삭제가 모두 이루어진경우 다시 삽입을 한다.
e|E)
echo -n "수정할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
echo -n "이름은 키값이므로 반드시 입력하셔야 합니다."
echo -n ""
continue
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
# 삭제 수행
grep -v -i "$NAME# $DBASE > $DBASE.new
mv $DBASE.net $DBASE
# 삽입 수행
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $DBASE
# 소팅 결과를 동일한 파일에 적용한다.
sort -o $DBASE $DBASE
;;
1.3.2. 검색 부분 보강하기
- 검색의 경우 이름검색만 있었는데, 이름, 직업, 전화번호까지 검색을 수행하게 한다.
- .*를 각 변수에 입력하는 이유는 grep .* filename 을 수행하면 cat filename과 동일하기 때문에 검색하고자 하는 단어가 null이 들어오는 것을 방지할 수 있다.
s|S)
echo -n "검색할 이름 : "
read NAME
if [ "$NAME" = "" ]
then
NAME=.*
fi
echo -n "검색할 직업 : "
read OCCU
if [ "$OCCU" = "" ]
then
OCCU=.*
fi
echo -n "검색할 전화번호 : "
read NUM
if [ "$NUM" = "" ]
then
NUM=.*
fi
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE | grep -i "$OCCU" | grep -i "$NUM"
echo "-----------------------------------"
echo -n " 엔터키를 누르세요"
read RSP
;;
1.3.3. 소팅을 분리하여 속도 개선하기
- 매번 데이터를 입력하고 소팅하고, 삭제하고 소팅하고, 수정하고 소팅하는 작업은 상당히 부하를 많이 준다. 그러므로 소팅이라는 별도 메뉴를 두어 소팅하는 것도 좋은 방법이다.
- 단, 앞에서 입력, 수정부분의 sort 처리는 삭제해야 한다.
t|T)
echo " Sorting 중 "
sort -o $DBASE $DBASE
;;
1.3.4. 반복 입력 하기
- 데이터를 입력하기 위해서 매번 메뉴를 선택하면 불편하다. 그러므로 반복해서 입력하게 수정하면 더욱 좋은 프로그램이 된다.
- 또한 매번 입력을 원본 데이터베이스에 저장하면 속도가 떨어진다.( 여러명이 사용하는 경우 ) 그러므로 새로운 파일에 만들고 이를 원본에 입력하는 방식을 사용한다.
- $$.add 는 프로세스 아이디를 이용한 파일을 생성한다. $$는 해당 프로세스 파일이다.
- ASK값이 y가 아닌경우 해당 파일을 $DBASE에 리다이렉트 시킨다.
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 입력 ] ====================="
echo -n ""
echo -n "이름 = "
read NAME
if [ "$NAME" = "" ]
then
echo -n "이름은 키값이므로 반드시 입력하셔야 합니다."
echo -n ""
continue
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo ""
echo "=============================================="
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $$.add
echo -n "Continue ? (y/n) (default=y) "
read ASK
if [ "$ASK" = "" ]
then
then ASK=y
fi
done
if [ -s $$.add ]
then
cat $$.add >> $DBASE
rm $$.add
fi
;;
=== 반복 삭제 하기===
- 삭제 역시 직접적으로 삭제를 수행하면 시간이 오래 걸리며, 입력을 위해 데이터를 사용하고 있다면 삭제에 문제가 발생 할 수 있다.
- 삭제 명령은 ex, ed Script를 이용하여 삭제를 수행한다.
d|D)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 삭제 ] ====================="
echo -n ""
echo -n "삭제할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo "/$NAME/d" >> $$.del
echo -n "Continue ? (y/n) (default = y) "
read ASK
if [ "$ASK" + "" ]
then
ASK=y
fi
done
if [ -s $$.del ]
then
echo "w" >> $$.del
ed $DBASE < $$.del
rm $$.del
fi
;;
1.3.5. 반복 수정 하기
- 수정 역시 ed script를 이용하여 간편하게 수정을 하면 속도 향상을 볼 수 있다.
e|E)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "수정할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo "/$NAME/c" >> $$.edit
echo "$NAME $OCCU $NUM" >> $$.edit
echo . >> $$.edit
echo -n "Continue ? (y/n) (default = y)"
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
if [ -s $$.edit ]
then
echo "w" >> $$.edit
ed $DBASE < $$.edit
rm $$.edit
fi
;;
1.3.6. 반복 검색 하기
s|S)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "검색할 이름 : "
read NAME
if [ "$NAME" = "" ]
then
NAME=.*
fi
echo -n "검색할 직업 : "
read OCCU
if [ "$OCCU" = "" ]
then
OCCU=.*
fi
echo -n "검색할 전화번호 : "
read NUM
if [ "$NUM" = "" ]
then
NUM=.*
fi
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE | grep -i "$OCCU" | grep -i "$NUM"
echo "-----------------------------------"
echo -n "Continue ? (y/n) (default=n)"
read ASK
if [ "$ASK" = "" ]
then
ASK=n
fi
done
;;
1.3.7. 전체 소스
#! /bin/sh
clear
DBASE="$HOME/shell/data/phonebook.db"
while :
do
echo -n "전화번호부
a : 입력
d : 삭제
e : 수정
s : 검색
v : 출력
t : 소팅
[enter] : 종료
원하시는 작업을 선택해 주십시오 ?(a, d, e, s, v, [enter]) : "
read RSP
case $RSP in
"") exit 0 ;;
a|A)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 입력 ] ====================="
echo -n ""
echo -n "이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo ""
echo "=============================================="
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $$.add
echo -n "Continue ? (y/n) (default=y) "
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
if [ -s $$.add ]
then
cat $$.add >> $DBASE
rm $$.add
fi
;;
d|D)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 삭제 ] ====================="
echo -n ""
echo -n "삭제할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo "/$NAME/d" >> $$.del
echo -n "Continue ? (y/n) (default = y) "
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
if [ -s $$.del ]
then
echo "w" >> $$.del
ed $DBASE < $$.del
rm $$.del
fi
;;
e|E)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "수정할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo "/$NAME/c" >> $$.edit
echo "$NAME $OCCU $NUM" >> $$.edit
echo . >> $$.edit
echo -n "Continue ? (y/n) (default = y)"
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
if [ -s $$.edit ]
then
echo "w" >> $$.edit
ed $DBASE < $$.edit
rm $$.edit
fi
;;
s|S)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "검색할 이름 : "
read NAME
if [ "$NAME" = "" ]
then
NAME=.*
fi
echo -n "검색할 직업 : "
read OCCU
if [ "$OCCU" = "" ]
then
OCCU=.*
fi
echo -n "검색할 전화번호 : "
read NUM
if [ "$NUM" = "" ]
then
NUM=.*
fi
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE | grep -i "$OCCU" | grep -i "$NUM"
echo "-----------------------------------"
echo -n "Continue ? (y/n) (default=n)"
read ASK
if [ "$ASK" = "" ]
then
ASK=n
fi
done
;;
v|V)
echo " 전화번호부 "
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
more $DBASE
echo "-----------------------------------"
echo -n "엔터를 누르시오"
read RSP
;;
t|T)
echo " Sorting 중 "
sort -o $DBASE $DBASE
;;
*)
echo "명령어가 틀렸습니다. 다시 입력해 주세요."
;;
esac
done
1.4. Version Up 2
- Unix, Linux는 멀티 사용자를 고려하여 설계되었다. 그러므로 이러한 멀티 유저를 고려한 프로그래밍이 필요하다.
- 이러한 멀티 유저에서 타인이 데이터베이스 파일을 사용하고 있다면 사용이 끝이날때까지 작업을 막아두는 것이 필요하다. 이때 사용하는 것이 Flag와 Semaphore이다.
1.4.1. 세마포어 사용하기
- 세마포어를 사용하기 위한 부분을 만들어 보면 다음과 같이 만들 수 있다.
- running이라는 임시 파일을 만들고, 이 임시파일이 존재하면 잠시 대기를 반복한다.
- sleep 2는 2초동안 프로세스를 대기하는 것을 말한다.
- 체크가 끝이나면 자신이 프로세스를 사용하도록 running을 만든다.
checkrun() {
while [ -f running ]
do
sleep 2
done
touch running
}
1.4.2. 세마포어가 필요한 작업 분리
- 추가작업
adding() {
if [ -s $$.add ]
then
checkrun
cat $$.add >> $DBASE 2 > /dev/null
rm $$.add 2 > /dev/null
rm running
fi
}
- 삭제 작업
deleting() {
if [ -s $$.del ]
then
checkrun
echo "w" >> $$.del
ed $DBASE < $$.del 2 > /dev/null
rm $$.del
rm.running
fi
}
- 수정 작업
deleting() {
if [ -s $$.del ]
then
checkrun
echo "w" >> $$.del
ed $DBASE < $$.edit 2 > /dev/null
rm $$.del
rm running
fi
}
- 소팅 작업
sorting() {
echo "Sorting 중"
checkrun
sort -o $DBASE $DBASE
rm running
}
1.4.3. Background 작업으로 만들기
- 작업을 수행 명령얼 내리고 기다리는 경우, 타인은 그 작업이 완료되기 전까지 프로그램을 사용할 수 없게 된다.
- 최악의 경우 한참동안 다른 작업을 수행할 수 없을 수 있다. 그러므로 이러한 처리를 백그라운드 작업으로 돌리고 다른 작업을 진행할 수 있을 수 있다.
- 백그라운드 작업들은 프로세스 스케줄링에 따라 실행되므로 여러 작업이 들어오는 순서대로 처리 될 수 있다.
-
백그라운드 작업은 &를 사용하여 처리하면 된다.
...
...
adding &
...
...
deleting &
...
...
editing &
...
...
sorting &
...
...
1.4.4. 마지막 소스
#! /bin/sh
clear
DBASE="$HOME/shell/data/phonebook.db"
checkrun() {
while [ -f running ]
do
sleep 2
done
touch running
}
adding() {
if [ -s $$.add ]
then
checkrun
cat $$.add >> $DBASE 2> /dev/null
rm $$.add 2 > /dev/null
rm running
fi
}
deleting() {
if [ -s $$.del ]
then
checkrun
echo "w" >> $$.del
ed $DBASE < $$.del 2> /dev/null
rm $$.del
rm running
fi
}
editing() {
if [ -s $$.edit ]
then
checkrun
echo "w" >> $$.edit 2> /dev/null
rm $$.edit
rm running
fi
}
sorting() {
checkrun
sort -o $DBASE $DBASE
rm running
}
while :
do
echo -n "전화번호부
a : 입력
d : 삭제
e : 수정
s : 검색
v : 출력
t : 소팅
[enter] : 종료
원하시는 작업을 선택해 주십시오 ?(a, d, e, s, v, [enter]) : "
read RSP
case $RSP in
"") exit 0 ;;
a|A)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 입력 ] ====================="
echo -n ""
echo -n "이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo ""
echo "=============================================="
# 형식을 지정하여 데이터베이스 파일에 리다이렉트 시킨킨다.
echo "$NAME $OCCU $NUM" >> $$.add
echo -n "Continue ? (y/n) (default=y) "
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
adding &
;;
d|D)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo "=============== [ 삭제 ] ====================="
echo -n ""
echo -n "삭제할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo "/$NAME/d" >> $$.del
echo -n "Continue ? (y/n) (default = y) "
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
deleting &
;;
e|E)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "수정할 이름 = "
read NAME
if [ "$NAME" = "" ]
then
break
fi
echo -n "직업 = "
read OCCU
echo -n "전화번호 = "
read NUM
echo "/$NAME/c" >> $$.edit
echo "$NAME $OCCU $NUM" >> $$.edit
echo . >> $$.edit
echo -n "Continue ? (y/n) (default = y)"
read ASK
if [ "$ASK" = "" ]
then
ASK=y
fi
done
editing &
;;
s|S)
ASK=y
while [ "$ASK" = "y" -o "$ASK" = "Y" ]
do
echo -n "검색할 이름 : "
read NAME
if [ "$NAME" = "" ]
then
NAME=.*
fi
echo -n "검색할 직업 : "
read OCCU
if [ "$OCCU" = "" ]
then
OCCU=.*
fi
echo -n "검색할 전화번호 : "
read NUM
if [ "$NUM" = "" ]
then
NUM=.*
fi
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
grep -i "$NAME" $DBASE | grep -i "$OCCU" | grep -i "$NUM"
echo "-----------------------------------"
echo -n "Continue ? (y/n) (default=n)"
read ASK
if [ "$ASK" = "" ]
then
ASK=n
fi
done
;;
v|V)
echo " 전화번호부 "
echo "-----------------------------------"
echo "이름 직업 전화번호 "
echo "-----------------------------------"
more $DBASE
echo "-----------------------------------"
echo -n "엔터를 누르시오"
read RSP
;;
t|T)
sorting &
;;
*)
echo "명령어가 틀렸습니다. 다시 입력해 주세요."
;;
esac
done
'Linux > 쉘프로그래밍' 카테고리의 다른 글
Shell 키보드 입력하기 (0) | 2008.10.15 |
---|---|
Shell 로 백업 처리하기 (0) | 2008.10.15 |
Shell Programming 기본 (1) | 2008.10.15 |