셸 스크립트 : 실행하고 싶은 명령어를 파일에 입력한 것
echo "hello";cd /;ls -l : 명령어를 ;로 연결하여 한 행으로 입력할 수 있다.
셸 스크립트에서 빈 행은 무시된다. 셔뱅 아래에 넣는다 보통.
\로 명령어를 여러 행으로 나눠서 입력할 수 있다.
echo \
"root"
셸에서도 \ 를 입력하고 enter 누르면 프롬프트가 > 로 변한다.
세컨더리 프롬프트 : 아직 커맨드 입력이 끝나지 않은 프롬프트. 이때 표시되는 프롬프트의 문자를 PS2로 설정할 수 있다.세컨 프롬프트에서도 \를 사용할 수 있다. 마지막에 enter를 누르면 전체 명령어가 실행된다.파이프라인으로 명령어 연결 시 | 뒤에 enter를 누르면 이어서 작성할 수 있다.
주석 : #주석 일시적으로 명령어 실행하지 않도록 하는 것을 코멘트 아웃이라 한다.
: 에러 발생.$appdir=/home/jisu/myapp
변수값을 참조할 때만 변수명 앞에 $를 붙여야 한다.
appdir = /home셸 스크립트는 대입 시 공백이 허용되지 않는다.
변수명에 사용할 수 있는 문자
알파벳, 숫자, 언더바
숫자는 첫 글자로 사용할 수 없다.
첫 글자에는 알파벳이나 언더스코어만 사용할 수 있다.
알파벳은 대소문자 모두 사용가능
환경 변수에는 대문자를 사용하고 그 외 일반 변수에는 소문자를 사용한다.
변수 사용 시 주의점
변수를 명확히 구분한다.
예로 변수_backup을 echo하고 싶은 경우, ${변수}_backup 으로 출력한다.
변숫값에 문자열을 연결하고 싶을 때는 문자열까지 변수 이름에 포함되어 해석되지 않도록 주의해야 한다.
변수명을 {}로 감싸주면 된다.
#!/bin/bash
filename=residue.dat
echo ${filename}_backup
→ residue.dat_backup 이 출력된다.
배시에서는 공백을 기준으로 명령어 인자를 구분한다.
cat file1 file2 : cat 명령어에 파일 두 개를 인자로 지정하면 각각 내용이 출력된다.
my file과 같이 공백을 포함하는 문자열을 인자 하나로 지정하고 싶은 경우 작은 따옴표나 큰 따옴표로 감싼다. 공백이 있어도 한 단어로 인식한다.
*도 쿼팅하면 셸의 와일드카드로 인식되지 않는다.
쿼팅하면 공백이나 메타 문자를 의도한 대로 사용할 수 있다.
grep ‘Be*r’ drink.txt : drink.txt에서 Be*r에 해당하는 행을 출력
#!/bin/bash
country=Korea
echo ‘I came from $country’
echo “I came from $country”
$ : 변수값을 꺼내온다는 의미이다.
작은 따옴표로 감싸면 $가 그대로 출력되고,
큰 따옴표로 감싸면 변수값을 꺼내온다.
vi에서 한 글자 교체하는 경우 r 를 이용한다.
큰 따옴표 사용 시 $ 앞에 \를 붙이면 문자 그대로 출력할 수 있다.
echo “I came from \$country”명령어의 출력 결과를 이용하고 싶을 때 명령어 치환을 사용하면
명령어를 실행하고 출력된 결과를 취득할 수 있다.
$() 또는 ` : 백쿼트를 이용하여 괄호 안에 실행하려는 명령어를 작성한다.
작성한 명령어를 실행하고 출력되는 표준 출력으로 치환된다.
백쿼트는 시작과 끝 위치를 파악하기 어렵다. 명령어 치환에서 명령어 치환을 사용하려면 /를 붙여야 한다.
man date를 사용하여 옵션을 확인할 수 있다.
`date %m` : 오늘 month 출력
`date +%Y` : 년도 출력
`date ‘+%Y-%m-%d’` : 년-월-일 출력. 작은 따옴표로 묶어주면 좋다.
`echo “Today is $(date ‘+%Y-%m-%d’)”` : Today is 2023-11-14
작은 따옴표는 $를 그대로 출력한다.
큰따옴표는 변수값을 불러온다.
$ 대신에 ` 로 묶으면 결과가 동일하다.
echo “Today is date ‘+%Y-%m-%d’” : Today is 2023-11-14
셸 스크립트에서도 $() 대신에 쓸 수 있다.
echo “Today is $(echo date)” : Today is date - $()로 치환
echo “Today is $(echo `date`)” : Today is 2023.11.14(화) - 백쿼트로 치환
echo “Today is `echo date`” : Today is date - 백쿼트로 치환
echo "Today is `echo `date`` " : Today is 2023.11.14(화) - 백쿼트로 치환
echo "Today is $(echo $(date))" : Today is 2023.11.14(화) - $()로 치환
백쿼트를 중첩으로 사용할 경우는 앞에 \를 붙여야 한다.
셸 스크립트에서 위치 파라미터는 셸 변수를 사용해 전달받은 인자를 다룰 수 있다.
$ ./parameters.sh aaa bbb ccc
------$0---------------$1---$2--$3
$0 : 숫자를 이름으로하는 변수로 셸 스크립트를실행할 때 지정한 인자가 각각 할당된다.


./parameters.sh * : 인자에 와일드카드로 지정하면 모든 값이 셸 스크립트에 전달한다.
$# : 인자 개수를 나타낸다.
./parameters.sh aa bb c : $# 란에는 3이 출력된다.$@, $*인자를 분할하지 않은 채 전체를 참조하고 싶은 경우 자동으로 분할된 인자를 참조할 수 있다.

전체 인자가 $@ 와 $*에 담긴다.
$@ : 각각 독립적인 문자열로 취급한다.
$* : 하나의 문자열로 취급
인자 전체를 출력하는 것은 같다. 보통은 $@로 한꺼번에 얻어와서 사용한다.
배시에서도 일반 프로그래밍 언어처럼 값에 의한 조건 분기, 반복처리를 기술할 수 있다.
wrapper : 입력 받은 인자를 그대로 지정하여 다른 명령어를 실행하는 셸 스크립트
커맨드 라인 인자와 관련된 셸 변수
$0: 셸 스크립트 파일 이름
#*: 모든 위치 파라미터. 큰따옴표로 감싸면 전체가 하나의 문자열이 된다.$1, $2..: 커맨드 라인 인자의 값$#: 위치 파라미터의 개수#@: 모든 위치 파라미터. 큰따옴표로 감싸면 각 문자열이 감싸진다.$0: 셸 스크립트 파일 이름
#*: 모든 위치 파라미터. 큰따옴표로 감싸면 전체가 하나의 문자열이 된다.
#!/bin/bash
if [ "$1" = "bin" ]; then
echo "OK"
else
echo "NG"
fi
들여쓰기 필수 아니다.
조건식에 if []; then 세미콜론을 붙어야 한다.
[] 의 전후에 반드시 공백이 있어야 한다.
[ : 배시의 내장 명령어이므로 공백이 필수이다.
[ : 조건식이 참이면 0, 아니면 0 이외의 수를 반환한다.
if 뒤에 오는 것은 조건식이 아니라 명령어이다. 명령어의 결과가 참일 때 실행된다.
elif를 사용할 수 있다.
명령어의 종료 상태
정상 종료 시 0, 에러 발생 시 0 이외의 값을 반환한다.
$? 명령어로 확인할 수 있다.
if문에 [ 가 아닌 다른 명령어를 입력할 수 있다.
grep -q 'bash' /etc/passwd 의 종료 상태가 0인 경우 실행된다.
-q : 검색 결과를 출력하지 않는 옵션이다. 종료 상태만 필요한 경우 사용한다.
#!/bin/bash
if grep -q 'bash' /etc/passwd;then
echo 'bash found'
fi
리눅스의 test 명령어는 [ 명령어와 유사한 기능을 제공한다.
유일한 차이점은 test 명령어를 사용할 때는 마지막 인자로 ] 를 지정하지 않아도 된다는 점이다.
if [ "$1" = "bin" ];then
if test "$1" = "bin";then
두 표현은 동일한 의미를 가진다.
[==test
문자열에 관한 평가 연산자
- str1 = str2
- str1 != str2
-nstr1 : str1이 빈 문자열이 아님-zstr1 : str1이 빈 문자열임
filename=$1
if [ -z "$filename" ];then # 변수 filename이 빈 문자열이면 실행한다.
filename="default.dat"
fi
정수에 관한 비교 연산자
- int1
-eqint2 : 같음- int1
-neint2 : 다름- int1
-ltint2 : 1이 2보다 작음- int1
-leint2 : 1이 2 이하임- int1
-gtint2 : 1이 2보다 큼- int1
-geint2 : 1이 2 이상임
파일 속성에 관한 비교 연산자
-efile : exist
-dfile : exist, 디렉토리
-hfile : 존재, 심볼릭 링크임
-Lfile : 존재, 심볼릭 링크임
-ffile : 존재, 일반 파일임
-rfile : 존재, 읽기 권한 부여됨
-wfile : 존재, 쓰기
-xfile : 존재, 실행
file1-ntfile2 : 1의 변경 시간이 2보다 최근임
file1-otfile2 : 1의 변경 시간이 2보다 오래됨
-d 연산자로 확인하여 메시지를 출력한다.#!/bin/bash
logir=/home/ldk/myapp/logs
if [ -d "$logdir" ]; then
echo "로그 디렉터리: $logdir"
else
echo "error: 로그 디렉터리가 존재하지 않음"
fi
결합 연산자
- 조건식1
-a조건식2 : and- 조건식1
-o조건식2 : or- ! 조건식 : 반대로. not
- () : 조건식을 그룹화
-o는-a보다 우선순위가 낮다.
if [ -d "$dir" -a \( "$dir" = "/home" -o "$dir" = "/etc" \) ]
=if [ (-d "$dir") -a \( "$dir" = "/home" -o "$dir" = "/etc" \) ]
(dir이 디렉터리이고,) (home 또는 etc인 경우) 를 and연산 하기 위해 괄호 사용했다. 메타문자이므로 이스케이프 문자를 붙여줘야 한다.
&& : 처음 인자가 false일 때 할 필요가 없다. 처음 인자가 true일때만 실행한다.
|| : 하나만 true여도 true이다. 처음 인자가 false일 때만 두 번째 인자 실행한다.
[ -f file.txt ] && cat file.txt : file.txt가 없는 경우 실행되지 않는다.
[ -f file.txt ] || touch file.txt : file.txt 가 없는 경우 두 번째 인자를 실행한다. 있는 경우 두 번째 인자를 실행하지 않는다.
하이픈 a로 바꾸기 시험에 출제.
-a(and)는 &&와 같다.
&&는 명령어 2개를 나열해야 한다.
|| : 앞에꺼가 참이면 뒤에껄 검사하지 않는다.
셸 스크립트의 종료 상태
셸 스크립트도 종료 상태를 반환할 수 있다.
특별히 지정하지 않으면 마지막으로 실행한 명령어의 종료 상태가 해당 셸 스크립트의 종료 상태가 된다.
명시적으로 종료 상태를 지정하는 방법
exit <종료 상태>
exit 명령어를 실행하면 지정한 종료 상태가 return 된다.
다른 프로그램에서 이 셸 스크립트를 호출했을 때 적절히 에러 처리를 할 수 있다.
exit 명령어에 아무것도 지정하지 않으면 셸 스크립트에서 마지막으로 실행된 명령어의 종료 상태가 반환된다.
for 변수 in 리스트
do
반복 처리
done
aaa, bbb, ccc 요소 세 개를 차례로 출력한다.#!/bin/bash
for name in aaa bbb ccc
do
echo $ name
done
./for.sh 를 실행하면
Aaa
Bbb
Ccc
이렇게 출력된다.
경로 확장
#!/bin/bash
for filename in *.html
do
head -n 1 "$filename" # 파일의 앞 부분을 보여줌.
done
seq 시작 숫자 마지막 숫자 : 수열 출력 명령어#!/bin/bash
for i in $(seq 1 5) # 1,2,3,4,5
do
touch "000${i}.txt" # 0001, 0002, 0003.. txt파일을 생성한다.
done
커맨드 라인 인자와 for
./parameters.sh readme.txt 38 "hello"
readme.txt
38
hello
parameters.sh : 모든 커맨드 라인 인자가 차례로 출력된다.
#!/bin/bash
for parameter in "$@" # 문자 단위로 인자 구분
do
echo "$parameter"
done
패턴을 차례로 확인하다 일치하는 패턴이 있으면 처리를 실행한다.
어느 패턴에도 일치하지 않으면 아무것도 실행하지 않고 case문을 벗어난다.
패턴과 세미콜론 사이에 실행하고자 하는 처리를 작성한다.
패턴은 )로 끝나야 한다.
case문의 마지막은 esac로 끝난다.
패턴 개수에는 제한이 없다.
사용법
case "$1" in
*.txt)
less "$1"
;;
*.sh)
vim "$1"
;;
*)
echo "not supported file : $1"
;;
esac
확장자가 sh이면 vim “$1”을 실행한다.
해당되는게 없으면 echo “not supported file : $1”

case에서 패턴을 지정할 때 와일드카드를 지정할 수 있다.
*는 임의의 문자열을 의미하며 ? 는임의의 한 문자를 의미한다.
마지막 패턴으로 *를 지정했다.
*는 빈 문자열을 포함하여 모든 문자열 패턴을 의미한다.
어떤 패턴에도 해당하지 않는 경우를 지정하기 위해 사용한다.
#!/bin/bash
case "$1" in
start | stop) #start 혹은 stop인 경우
echo "OK"
;;
*) # 그 외 경우
echo "NG"
;;
esac
|로 기술한 여러 패턴 중 한 패턴에 일치하면 블록의 내용이 실행된다.
start과 stop 둘 중 하나가 지정되면 OK가 출력된다.
#!/bin/bash
i=1
while [ "$i" -le 10 ] #i가 less than equal to 10일 때 실행한다.
do
echo "$i" #i 출력
i=$((i+2)) #i=i+2
done
$(()) : 배시 셸의 산술 연산자이다.
$((i+2)) : `expr $i + 2` 와 동일하다.
sh기반에서는 expr 외부 명령어를 사용해야 한다. 이 경우 처리 속도가 느리고 가독성이 떨어진다.
셸 스크립트 작성 시 똑같은 처리를 여러 번 중복하여 입력하는 경우 발생.
중복되는 처리를 함수로 정의하면 코드가 깔끔해진다.
함수 이름만으로 처리를 실행할 수 있다.
homesize라는 셸 함수를 호출하고 있다.
du -h | tail -n 1 : 각 디렉토리의 디스크 사용량이 나온다.
-h 로 사용량 단위를 human-readable하게 출력한다.
tail로 현재 디렉토리 사용량만 출력한다.
#!/bin/bash
homesize() # 함수 정의
{
date
du -h | tail -n 1
}
homesize # 함수 호출
정의 전 호출할 경우 에러가 발생한다. 반드시 호출 전에 정의해야 한다.
셸 함수 안에서도 위치 파라미터 $1, $2 를 사용할 수 있음
위치 파라미터에는 커맨드 라인의 인자가 아니라 함수의 인자값이 대입된다.



커맨드 라인에 아무것도 지정하지 않았지만 함수를 호출할 때 지정한 인자 값이 위치 파라미터에 대입되어 있는 것을 알 수 있다.
함수를 호출할 때 인자가 위치 파라미터에 대입된다.
$0에는 함수 이름이 아닌 셸 스크립트의 이름이 들어있다.
$0은 위치 파라미터가 아닌 특수 파라미터이다.
마지막으로 실행한 명령어의 종료 상태가 셸 함수의 종료 상태가 된다.
명시적으로 값을 반환하려면 return을 사용한다.
return이 실행되면 셸 함수의 처리가 종료되고 호출한 곳으로 실행 흐름이 돌아간다
#!/bin/bash
chechparam()
{
if [ -z "$1" ]; then # 인자가 안들어오면 return 1
return 1
fi
ls "$1" # 인자가 있으면 ls 실행
}
chechparam /home
echo "$?"
1
ls:aaa에 접근할 수 없습니다.
2
user1 user2
0