출처 : [따배셸 5~](Youtube)
Script
라는 것은 하나의 파일에 기존에 존재하는 명령어를 집어넣어서 순차적으로 해석해서 실행하는 것을 말한다. 대표적으로 shell script, curl script가 있다. 일반적으로 프로그램은 소스코드를 compiler가 compile해서 binary 명령어를 만들어서 동작시키게 해주는 것을 말한다.
Shell Script
는 리눅스 command를 모아놓은 ASCII 텍스트 파일이다. Shell program
이라는 말과 혼용해서 쓰기도 하는데 shell program은 for,while,if..등의 프로그램 문법을 넣어서 좀 더 프로그램처럼 만들어 놓은 것을 가리키는 것이 일반적이다.
Shell Script를 실행하게 되면 Sub shell에서 동작한다. Sub shell이라는 것은 기존에 사용하고 있는 로그인 shell에서 실행되는 shell이라고 할 수 있다. 그래서 로그인 shell과 다른 shell을 사용할 수 있다. shell script의 첫번째 줄에 #!/bin/bash
를 작성하게 되면 shell script는 bash sub shell에서 실행된다. 또한 #
은 주석의 기능을 하게된다.
Shell Script를 작성하게 되면 실행 퍼미션을 할당해줘야 실행가능하다. 파일에 실행 퍼미션을 주기 위해선 chmod +x [filename]
을 해주면 된다.(+ 뒤에는 r,w,x 올 수 있음) 실행 퍼미션을 준 뒤 shell script를 실행하게되면 file.sh
실행이 안될 수도 있다. 이 경우는 PATH에 현재 디렉토리가 등록이 되어 있지 않은 경우이기 때문에 PATH에 해당 경로를 추가해주거나 ./file.sh
와같이 상대경로를 명시해주거나 절대경로를 명시해주면된다.
cat >file.sh
ls > "/tmp/`date +%Y%M%D`.txt"
echo
CTRL+d
vi 편집기를 이용해 file.sh 를 직접 작성해 주어도 되지만 cat >file.sh
를 사용해 여러줄을 작성할 수도있다. 이때 작성이 끝났으면 CTRL+d
를 통해 stin이 종료되었음을 알려주면된다. (CTRL+c
는 프로세스를 종료하는 것을 알려줌)
<<EOF cat >file.sh
ls > "/tmp/`date +%Y%M%D`.txt"
echo
EOF
위와 같은 방법도 사용할 수 있는데 <<tag
here document를 사용할수도 있다. heredoc은 입력 스트림에 텍스트를 입력시켜주는 역할을 하며 cat은 이것을 가져와 내용을 file.sh에 보내준다. <<tag
의 다음줄 부터 tag
까지의 내용이 입력 스트림에 들어간다.
shell script 또한 argument를 입력으로 받을 수 있다. 그 argument는 입력 순서대로 $1,$2...${10}... 에 저장되게 된다. 그 외에도 $0 는 shell script의 이름, $#은 입력된 argument의 수, $@,$* 는 입력된 argument의 list가 저장된다. 이러한 것을 Positional Paramenter
라고한다. Positional parameter는 쉘 스크립트 내에서 local variable로 사용할 수 있다. Shell script를 실행할때 argument를 입력해주는 것 뿐만아니라 set
명령어를 통해 설정할 수도 있다.
set 1 2 3 # 차례대로 $1, $2, $3에 저장됨
set -- -1 -2 -3 # arugument 에 -를 포함할 경우 `set --`를 해줘야함
Special shell variables
라는 특수한 shell variables도 있다. $$
는 로그인 shell 의 PID, $PWD
는 현재 작업 디렉토리, $PPID
는 부모 프로세스의 ID를 나타낸다.
echo
: print texts to standard ouput
echo -n # echo는 원래 자동 줄바꿈 기능이 있음. 줄바꿈을 하고싶지 않을때 씀
echo -e # backslash escape 문자를 해석하여 특별한 의미를 지정한다.(Quotation 에 포함되어야함)
\t : tab
\n : 줄바꿈
\a : alert(bell) 벨 소리남
++ 변수뒤에 바로 붙여서 text를 print하고싶으면 echo "${var}text" 처럼하면 됨
read
: read texts from standard input
read -n : 지정한 문자수까지만 입력을 받고 그것을 초과하면 입력을 중단한다.
read -t : 지정된 시간안에 입력받는다.
read -s : silent mode로 입력하는 글자가 보이지 않는다.
ex) read -n5 -t5 -s password : 최대 5글자를 5초동안 입력받고 그 값을 password 변수에 저장한다.
read -n5 a b : a, b 변수에 대한 입력을 최대 5글자 받는다. a,b 변수를 구분하기 위해 blank가 필요해 두 변수의 길이를 합친 것은 4글자를 못 넘음
printf
는 서식 format에 맞춰서 출력할 수 있다. C언어의 printf 함수와 동일.
%d or %i : 숫자
%s : 문자열
%f : 실수형 숫자 (%.3f : 소수점 3째자리까지 출력)
%10s, %10s, %10i, %10f : 10칸을 할당, 오른쪽 정렬
%-10s, %-10s, %-10i, %-10f : 10칸을 할당, 왼쪽 정렬
직전 프로그램 혹은 명령어가 정상적으로 종료되었는지, 정상적으로 종료되지 않았다면 어떤 문제가 있었는지는 $?
라는 변수에 저장된다.$? 값이 0이면 성공적으로 종료하였음을 의미하고 1~255의 값을 가지만 실패로 종료하였음을 의미한다.
0 : 프로그램 또는 명령이 성공적으로 종료
1 : 일반에러
2 : Syntax error
126 : 명령을 실행할 수 없음
127 : 명령(파일)이 존재하지 않음
128+N : 시그널 N으로 종료된 경우
시그널 : 프로세스에게 어떤 이벤트의 발생을 알리기 위해 전달되는 소프트웨어 인터럽트이다. 예를들어 강제 종료 명령어인 kill -9
의 9는 signal에 해당하고 signal 9은 강제 종료를 의미한다. 프로세스가 실행중에 ctrl+z를 누르면 일시정지(다시 시작하려면 fg,bg) 되며 이때 signal 20이 전달된다. 프로세스가 실행중에 ctrl+c를 누르면 실행종료되며 이때 signal 2가 전달된다.
쉘 스크립트를 특정한 이유로 종료하고 싶을때 exit
명령어를 쓸 수 있다. exit 명령어를 사용하면 그 프로세스는 종료되며 종료값을 $?에 반환해 준다.
test
는 비교연산자를 활용하게 해주는 명령어이다. 보통 if 문의 조건을 나타낼때 사용하며 test 명령어
,[ 명령어 ]
의 형태로 사용한다. test 명령어는 다양한 연산자를 지원한다.
-f file : file이 파일이면 true를 리턴
-x file : file이 실행가능하면 true를 리턴
test $x -gt 5 # 변수 x가 5보다 크다면
[ $x -gt 5 ] # 변수 x가 5보다 크다면
if
는 조건문이며 위의 비교연산자와 조합하여 사용한다.
if 비교연산자
then # true이면 command1을 실행
command1
else # false이면 commad2를 실행, command2가 없으면 생략가능
command2
fi # if문의 종료를 알림
case
는 조건이 여러개일때 사용하면 좋다.
case "$variable" in # 변수 variable이
pattern1) command1;; # patter1이면 command1, 하나의 패턴이 끝날때마다 ;; 붙여줘야함
pattern2) command2;;
*) command3;; # 나머지 경우에
esac # case문의 종료를 알림
No,no
를 하나의 패턴에 모두 넣고싶을 수 있다. 그땐 패턴을 [Nn]o
와 같이 넣어주면된다.
이 때 []
를 wildcard
라고 하며 *
,?
가 있다.
[]
: 괄호안의 문자중 하나를 뜻 ex) [ab]
: a 혹은 b, [a-c]
: a~c중 하나
?
: 아무 문자 하나를 의미
*
: 아무 문자의 집합을 의미
{}
: wildcard는 아님. 반복의 이미를 담고 있음 ex) mkdir file{1,2,3} : file1,file2,file3을 생성, mkidr file{1..3} : file1 ~ file3 생성
expr 연산식
의 형태로 사용$
를 써줘야한다.let 연산식
, ((연산식))
의 형태로 사용$
를 안써줘도 된다.$((연산식))
은 계산을 수행하고 결과를 반환한다. x=1
expr 1 + 1 # 2를 출력
expr $x + 1 # 2를 출력
x=`expr $x + 1` 결과: x에 2를 대입
x=1
# 아래의 6개는 모두 동일한 명령 x에 2를 대입
let x=x+1
let x++
let x+=1
((x=x+1))
((x++))
((x+=1))
# 아래의 3개는 x에 2를 대입하고 2라는 숫자로 인식(마치 $변수처럼 인식, 출력과 다른 의미)
$((x=x+1))
$((x++))
$((x+=1))
while
과 until
은 비슷한 구조를 띄고 있다. 모두 do ~ done 사이의 command를 조건을 확인하고 수행한다. 차이점은 while
은 조건을 만족하지 않으면 종료고 until
은 조건을 만족하면 종료된다. break
를 통해 loop을 탈출할 수도 있다.while 조건명령어
do
commands
done
until 조건명령어
do
commands
done
실습 : username을 입력받아 해당 user가 있으면 다시 username을 입력받는다. 없다면 해당 user를 만들고 종료된다. #!/bin/bash
printf "New username: "
read username
while getent passwd $username &> /dev/null
do
echo "이미 해당 이름 존재, 다시 입력바람"
printf "New username: "
read username
done
sudo useradd -m -s /bin/bash $username
getent
는 지정된 database에 대한 정보를 출력해준다. username을 입력받으면 username에 해당하는 user의 정보만 출력해준다. 위와 같이 조건문에 종료코드를 활용할 수 있다. 실습 : user를 삭제하는 script#!/bin/bash
printf "username to remove: "
read username
until getent passwd $username &> /dev/null
do
echo "해당 이름 없음, 다시 입력바람"
printf "username to remove: "
read username
done
sudo userdel -r $username 2> /dev/null
for 변수명 in [LIST]
do
commands
done
for NUM in $(seq 5)
do
echo "NUM:$NUM"
done
=======동일==========
for NUM in 1 2 3 4 5
do
echo "NUM:$NUM"
done
실습 1 : ~/backup 디렉토리를 만들어서 현재 디렉토리의 파일을 전부 복사if [ ! -d ~/backup ]
then
mkdir ~/backup
fi
for file in *
do
if [ $file == backup ]
then
continue
fi
cp -rf file
done
실습 2 : 디렉토리를 입력받아 그 안에 file이 몇 개인지 directory가 몇개인지 확인
printf "Input a directory name: "
read dir
while [ ! -d $dir ]
do
echo "It's not a directory"
printf "Input a directory name: "
read dir
done
files=0
dirs=0
for NAME in ls $dir
do
if [ -f "NAME" ]
then
((files++))
fi
if [ -d "NAME" ]
then
((dirs++))
fi
done
echo "---------------"
echo "echo files : $files"
echo "echo dirs : $dirs"
echo "---------------"