일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 하체
- 달리기
- Shell
- 대구
- Python
- zabbix
- 유산소
- GitHub
- 힐링
- 건대입구역
- 대전
- 오답노트
- Podman
- Run The Bridge
- Grafana
- 러닝
- Linux
- docker
- DSEC
- 한강
- 10km
- 소모임
- 정보처리기사
- 중식
- 자전거
- 2021
- Kubernetes
- 성수대교
- 맛집
- 뚝섬유원지
- Today
- Total
Run The Bridge
shell script master -5- 본문
0. 조건문(if..else.fi)
if문은 'if 조건문; then fi'으로 이루어져 있다.
if true; then
echo true
else
echo false
fi
---
다음과 같이 한 줄로도 사용할 수 있다.
if true; then echo true; else echo false; fi
true
if문은 사용자의 용도에 따라 다양하게 사용되므로 천천히 배워보자.
1. [..] vs [[..]]
tom, deniro라는 변수에 값을 할당한다.
그 후 대괄호 비교를 사용해 두 문자열을 비교한다.
tom="Tom hanks"
deniro="Robert Deniro"
[ $tom > $deniro ]
-bash: $deniro: ambiguous redirect # 오류 발생
※ [..] 안에서 '<,>'문자는 redirect로 해석된다.
다음과 같은 방법으로 해결할 수 있다.
바로 대괄호 두 개를 사용해준다. 이러면 비교로 사용할 수 있다.
[[ $tom > $deniro ]]
echo $?
0
---
'=' 기호를 사용해도 오류가 나온다.
[ $tom = $deniro ]
-bash: [: too many arguments
다음과 같은 방법으로 해결할 수 있다. 인용부호("")를 사용해준다.
[ "$tom" = "$deniro" ]
echo $?
1
※ TIp. [[]]를 사용하면 ""를 생략해도 된다.
2. 인용부호 사용 시 주의사항
다음과 같은 명령어를 입력한다.
VAR에 빈 문자로 초기화하였다.
VAR=; if [ $VAR = ""]; then echo true; else echo false;fi
-bash: [: : unary operator expected
false
스크립트를 작성해서 돌려보면 $VAR에 어떤 값이 들어가는지 알 수 있다.
bash -x VAR.sh
+ VAR=
+ '[' = '' ']'
VAR.sh: line 3: [: =: unary operator expected
+ echo false
false
우리는 다음과 같은 방법으로 해결해 줄 수 있다. → 인용부호("")를 사용해준다.
VAR=; if [ "$VAR" = "" ];then echo true; else echo false;fi
true
스크립트를 수정하고 다시 돌려본다. → 빈 문자가 입력되었다는 걸 알 수 있다.
bash -x VAR.sh
+ VAR=
+ '[' '' = '' ']'
+ echo true
true
위에서 마찬가지로 '[[]]'를 사용해서 생략 가능하다.
VAR=; if [[ $VAR = "" ]]; then echo true; else echo false; fi
true
3. 비교 메타 문자열
if [ ! -f "hello.txt.bak" ]; then # hello.txt.bak라는 파일이 존재하지 않으면
> cp "hello.txt" "hello.txt.bak" # hello.txt를 hello.txt.bak으로 복사한다.
> fi # if문 종료
복사가 되었다는 것을 알 수 있다.
-rw-r--r--. 1 root root 6 Jan 23 23:02 hello.txt.bak
-f 이외에 사용하는 메타 문자는 다음과 같다.
Name | Description |
-e FILE | 파일이 있는 경우 True |
-f FILE | 파일이 일반 파일인 경우 True |
-d FILE | 파일이 디렉터리인 경우 True |
-h FILE | 파일이 심볼 링크인 경우 True |
-p FILE | 파이프가 있는 경우 True |
-r FILE | 사용자가 파일을 읽을 수 있는 경우 True |
-s FILE | 파일이 존재하며 비어 있지 않은 경우 True |
-t FD | 터미널에서 FD가 열려 있는 경우 True |
-w FILE | 사용자가 파일을 쓸 수 있는 경우 True |
---
예시를 들어보자.
if (( $? )); then # 먼저 사용한 조건이 거짓에 한해서
> echo 'Please run using "bash" or "sh", but not "." or "source"' >&2 # echo가 실행된다.
> exit 1
> fi
---
디렉터리에 파일이 존재하는지를 체크하는 if문 + 명령문을 if문안에 넣을 때는 $()로 묶어준다는 것도 알고 가자.
if [[ $(ls -A) ]]; then
> echo "there are files"
> else
> echo "no files found"
> fi
there are files
---
다음과 같은 sleep.sh를 실행한다.
#!/bin/bash
while true; do
sleep 1;
done
./sleep.sh & # 백그라운드로 실행
ps
PID TTY TIME CMD
73865 pts/2 00:00:00 bash
116149 pts/2 00:00:00 sleep.sh
116217 pts/2 00:00:00 ps
result=`ps aux | grep -i "sleep.sh" | grep -v "grep" | wc -l` # sleep.sh 파일이 동작하는지 확인하는 스크립트
if [ $result -ge 1 ]; then echo "script is running"; else echo "script is not running"; fi
script is running
다시 동작중인 sleep를 kill 명령어로 죽이고 다시 명령어를 입력해본다.
---
result에 변수값이 이미 할당되어 있어서 재입력해주고 if문을 실행한다.
result=`ps aux | grep -i "sleep.sh" | grep -v "grep" | wc -l` # sleep.sh 파일이 동작하는지 확인하는 스크립트
if [ $result -ge 1 ]; then echo "script is running"; else echo "script is not running"; fi
script is not running
예상대로 실행하지 않다고 나오는 것을 볼 수 있다.
Name | Description |
-x FILE | 파일이 실행 가능한 경우 True |
-O FILE | 파일이 사용자가 효과적으로 소유하는 경우 True |
-G FILE | 파일이 그룹에 의해 효과적으로 소유되는 경우 True |
FILE -nt FILE | 첫 번째 파일이 두 번째 파일보다 최신이면 True |
FILE -ot FILE | 첫 번째 파일이 두 번째 파일보다 오래된 경우 True |
-z STRING | 문자열이 비어 있으면 True(length =0 0) |
-n STRING | 문자열이 비어 있지 않은 경우 True |
STRING = STRING | 첫 번째 문자열이 두 번쨰 문자열과 동일한 경우 True |
STRING != STRING | 첫 번째 문자열이 두 번째 문자열과 동일하지 않은 경우 True |
STRING < STRING | 첫 번째 문자열이 두 번째 문자열보다 먼저 정렬되는 경우 True |
STRING > STRING |
첫 번째 문자열이 두 번째 문자열 뒤에 정렬되는 경우 True |
EXPR -a EXPR | 두 식이 모두 참이면 참(logical AND) |
EXPR -o EXPR | 두 식이 하나가 참이면 참(logical OR) |
! EXPR | 표현식의 결과를 반전(logical NOT) |
INT -eq INT | 두 정수가 동일한 경우 True |
INT -ne INT | 두 정수가 동일하지 않은 경우 True |
INT -lt INT | 첫 번째 정수가 두 번째 정수보다 작은 경우 True |
INT -gt INT | 첫 번째 정수가 두 번째 정수보다 큰 경우 True |
INT -le INT | 첫 번째 정수가 두 번째 정수보다 작거나 같으면 True |
INT -ge INT | 첫 번째 정수가 두 번쨰 정수보다 크거나 같으면 True |
Name | Description |
STRING = (OR ==) PATTERN | `[`과 같은 문자열 비교는 아니지만 패턴 일치가 수행된다. 문자열이 글로브 패턴과 일치하는 경우 True |
STRING != PATTERN | `[`과 같은 문자열 비교는 아니지만 패턴 일치가 수행된다. 문자열이 글로브 패턴과 일치하지 않은 경우 True |
STRING =~ REGEX | 문자열이 regex 패턴과 일치하는 경우 True |
(EXPR) | 괄호를 사용하여 평가 우선 순위를 변경할 수 있다. |
EXPR && EXPR | 테스트의 `-a` 연산자와 매우 유사하지만 첫 번째 표현식이 이미 거짓으로 판명되면 두 번쨰 표현식을 평가하지 않는다. |
EXPR || EXPR | 테스트의 `-o` 연산자와 매우 유사하지만 첫 번째 표현식이 이미 사실인 경우 두 번쨰 표현식을 평가하지 않는다. |
4. 실습(DRILL)
사용자의 전달 인자를 체크하여 사용법을 출력하도록 하는 스크립트를 만들어본다.
./goodday.sh # 전달인자 x
usage: ./goodday.sh directory
./goodday.sh dir # 전달인자 o
Have a nice day!
---
간단하게 전달인자 1개를 보고, 그 값이 -z(zero)이면 if문, 아닐 시 else문을 출력한다.
#!/bin/bash
if [ -z $1 ];then
echo "you need to input factor"
else
echo "Your input factor ${1}"
fi
친절하게 어떤 인자를 입력했는지 알려준다 ㅎㅎ
./factor.sh
you need to input factor
./factor.sh test
Your input factor test
5. while 루프
while true; do done
---
hello world를 1초마다 찍는 while문
while true; do
> echo "hello world"
> sleep 1
> done
hello world
hello world
hello world
hello world
---
while문에서 잠깐 벗어났지만, eval을 사용하면 {}안에 $COUNT가 변수로 선언되어 동작한다.
for no in `eval echo {0..$COUNT}`; do
> echo $no
> done
0
1
2
3
4
5
6
7
8
9
10
---
중괄호 확장을 사용할 땐 위에서 배웠듯이 eval을 사용해야 한다.
eval echo {0..$COUNT}
0 1 2 3 4 5 6 7 8 9 10
---
6. DRILL
1부터 10까지 더하는 함수를 만들어본다.
나는 약간 변형해서 사용자의 입력만큼 더하는 스크립트를 작성했다.
#!/bin/bash
result=0 # 빈 값 선언
read -p "your favorite number: " # 사용자의 입력
for num in `eval echo {0..$REPLY}` # 해당 값 만큼 for문 진행
do
result=$(($num + $result)) # 더하기
done
echo $result # 출력
하면서 추가로 배웠던 점이..물론 앞에서 했겠지만
1. linux에서 변수를 할당할 때 띄어쓰기가 있으면 안된다.(result = 0, x)
2. linux 더하기는 $(($ + $))로 구성된다. 물론 다른방법이 존재하겠지만.
3. eval를 쓰고 {0..$REPLY)를 사용할 때 앞에 echo가 존재해야 한다.
./while_DRILL.sh
your favorite number: 5
15
./while_DRILL.sh
your favorite number: 10
55
7. for..in 루프
classroom=(desk pen note chair book)
---
배열 내용 출력
echo ${classroom[@]}
desk pen note chair book
---
배열에 pen이 들어가 있으면 공백으로 바꾸는 코드
for i in ${!classroom[@]}; # '!'를 사용하여 배열의 참조 인덱스 값을 가져온다.
do
if [ "${classroom[$i]}" = 'pen' ]; then
classroom[$i]='';
fi;
done
echo ${classroom[@]}
desk note chair book
---
이 부분을 조금 더 파헤쳐보자.
일단 다시 배열을 선언해준다.
for i in ${!classroom[@]};
예상 했던대로 참조 인덱스 값이면 0, 1, 2, 3, 4 였다.
파이썬의 len참수를 사용하면 0, len 길이만큼 가져올 수 있는데, linux의 length라고 봐도 될 듯 하다.
for i in ${!classroom[@]}; do
> echo $i
> done
0
1
2
3
4
8. 실습(DRILL)
imagemagick을 이용하여 PNG 파일을 만들어보세요.
- 이미지 편집
- 이미지 필터
- 이미지 합성
PASS
9. for((;;)) 루프
c언어의 for loop문을 똑같이 사용할 수 있다.
for((i=0;i<${#mystr};i++)); do
> c="${mystr:$i:1}"
> echo "$c"
> done
H
e
l
l
o
W
o
r
l
d
---
#을 써서 띄어쓰기 포함 문자열의 length을 얻어올 수 있다.
echo ${#mystr}
11
---
mystr="Hello World"
012345678910
echo ${mystr:1:1} # 1번째 글자부터 1글자 출력
e
echo ${mystr:2:1} # 2번째 글자부터 1글자 출력
l
echo ${mystr:2:2} # 2번째 글자부터 2글자 출력
ll
echo ${mystr:2:3} # 2번째 글자부터 글자 출력
llo
10. 명령어(date)
date +"%Y-%m-%d" # 년, 월, 일 출력
2022-01-26
---
구분 기호는 자유롭게 사용하면 된다.
date +"%Y/%m/%d"
2022/01/26
---
시간도 뽑아낼 수 있다.
date +"%Y-%m-%d %r"
2022-01-26 12:46:47 AM
---
요일도 뽑아 낼 수 있다.
date +"%Y-%m-%d %H:%M %A"
2022-01-26 00:47 Wednesday
---
다음과 같이 형식화된 출력도 가능
date "+DATE: %Y-%m-%d%nTIME: %H:%M:%S"
DATE: 2022-01-26
TIME: 00:48:13
13. 실습(DRILL)
커맨드라인 시계를 만들어보세요
나는 그냥 좀 이상하게 만들었다..
while true; do
date "+DATE: %Y-%m-%d %H:%M:%S"
sleep 1
clear
done
---
변수에 넣어서 출력해야 되는 것 까진 생각했는데, 커맨드 라인을 보존하면서 출력하는게 어려웠다.
근데 강사님은 echo문을 써서 만들었다.
#/bin/bash
while true; do
TIME=$(date "+DATE: %Y-%m-%d %H:%M:%S");
echo -ne "${TIME}\\r";
done
14. 루프 문과 glob
다음과 같이 해당 파일을 for문을 이용해 지워본다.
root@kube-master ~/shell_script/mydir # ll
total 0
-rw-r--r--. 1 root root 0 Jan 6 22:12 Gone
-rw-r--r--. 1 root root 0 Jan 6 22:12 Gone With the Wind.mp3
-rw-r--r--. 1 root root 0 Jan 6 22:12 the
-rw-r--r--. 1 root root 0 Jan 6 22:12 Wind.mp3
-rw-r--r--. 1 root root 0 Jan 6 22:12 With
for file in $(ls *.mp3); do
rm "$file"
done
---
이게 강사님 영상에는 안 지워지는데, 버전에 따라 달라지나..? 삭제되었다
root@kube-master ~/shell_script/mydir # ll
total 0
-rw-r--r--. 1 root root 0 Jan 6 22:12 Gone With the Wind.mp3
-rw-r--r--. 1 root root 0 Jan 6 22:12 the
-rw-r--r--. 1 root root 0 Jan 6 22:12 Wind.mp3
-rw-r--r--. 1 root root 0 Jan 6 22:12 With
---
아래의 간단한 방법으로 삭제할 수 있다.
for file in *.mp3 do
rm "$file"
done
---
아래 명령을 실행해 file에 어떤 값이 담기는지 확인한다.
for file in *.mp3
do
echo ${file}
done
for file in *.mp3
> do
> echo ${file}
> done
Gone With the Wind.mp3
Wind.mp3
15. 실습(DRILL)
for문을 사용해 현재 경로내 모든 파일의 백업파일을 만들어 보세요
ll
total 0
-rw-r--r--. 1 root root 0 Jan 6 22:16 Balloon.jpg
-rw-r--r--. 1 root root 0 Jan 6 22:16 Candy.jpg
-rw-r--r--. 1 root root 0 Jan 6 22:16 glob.gif
-rw-r--r--. 1 root root 0 Jan 6 22:16 settings_down.png
-rw-r--r--. 1 root root 0 Jan 6 22:16 settings_up.png
-rw-r--r--. 1 root root 0 Jan 6 22:16 shadingimage.tiff
-rw-r--r--. 1 root root 0 Jan 6 22:16 smaller.tiff
---
성공?
total 24
-rw-r--r--. 1 root root 0 Jan 6 22:16 settings_up.png
-rw-r--r--. 1 root root 0 Jan 6 22:16 settings_down.png
-rw-r--r--. 1 root root 0 Jan 6 22:16 glob.gif
-rw-r--r--. 1 root root 0 Jan 6 22:16 Candy.jpg
-rw-r--r--. 1 root root 0 Jan 6 22:16 Balloon.jpg
-rw-r--r--. 1 root root 0 Jan 6 22:16 smaller.tiff
-rw-r--r--. 1 root root 0 Jan 6 22:16 shadingimage.tiff
drwxr-xr-x. 14 root root 4096 Jan 26 01:09 ..
-rwxr-xr-x. 1 root root 94 Jan 26 01:24 bakcup.sh
-rw-r--r--. 1 root root 0 Jan 26 01:24 Balloon.jpg.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 Candy.jpg.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 settings_down.png.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 glob.gif.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 shadingimage.tiff.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 settings_up.png.bak
-rw-r--r--. 1 root root 0 Jan 26 01:24 smaller.tiff.bak
-rw-------. 1 root root 12288 Jan 26 01:24 .bakcup.sh.swp
drwxr-xr-x. 2 root root 4096 Jan 26 01:25 .
---
script는 다음과 같다.
위에서 알려주셨듯이 확장자 명이 다양해서 *.*로 모든 파일을 backup이라는 변수에 하나씩 넣고
특정 변수에 할당시킨다.
그리고 cp명령으로 복사하면 끗~
#!/bin/bash
for backup in *.*
do
backup_file=$backup
cp ${backup} ${backup_file}.bak
done
16. 명령어(seq)
seq(시크)라는 명령어는 순서를 출력하기 아주 좋은 명령어
seq 1 10
1
2
3
4
5
6
7
8
9
10
---
숫자를 2단계씩 건너뛸 수 있다. (파이썬에도 리스트를 출력할 때 인덱스 번호 컨트롤로 존재하죠? 0:10:2)
seq 0 2 10
0
2
4
6
8
10
---
-s(separate)를 사용해서 구분 기호 콤마(,)를 추가할 수 있다.
seq -s, 1 1 10
1,2,3,4,5,6,7,8,9,10
---
숫자를 감소시키는 것 도 가능하다.
seq -s, 10 -1 1
10,9,8,7,6,5,4,3,2,1
17. 실습(DRILL)
seq와 printf 그리고 for을 이용하여 다음을 출력하세요
001 002 003 004 005 006 007 008 009 010
---
간단하게 해결할 수 있었다.
printf "%03d\t" 라는 유용한 기능이 정말 시간 단축을 많이 시켜 주었다.
#!/bin/bash
read -p "Your favorite number: " # 변수를 선언하지 않으면 $REPLY에 들어 가는거 아시죠? ㅎㅎ
for i in `eval echo {1..$REPLY}`
do
printf "%03d\t" $i
done
이렇게 사용자 입력에 맞게 출력이 가능하다.
18. case
read -p "enter any string: " # 아무 글자나 입력합니다.
c언어의 case문과는 좀 다르게 헷갈린다.
')'을 기준으로 case를 적고 조건을 명시한다.
'*)'을 적어주면 'if else'문에서 else구문이라고 보면 된다.
마지막에는 'case'를 뒤짚은 'esac'를 적어주면 된다.
그리고 ';;' 2개 적는거 잊으면 안된다!
case $REPLY in
+([[:digit:]]) ) echo "digits" ;;
*) echo "not digits" ;;
esac
솔직히 이 예시보다..구글에서 더 간단한 예시를 보는게 이해가 빠를 듯 하다.
19. 실습(DRILL)
PASS
#!/bin/bash
read -s -n 1 -p "You really want to exit? " response
case "$response" in
Y|y)echo YES;;
N|n)echo NO;;
*)kill -SIGKILL $$;;
esac
20. getopts(부족)
사용자로부터 전달받은 인자를 처리하기 위해 사용한다.
전달인자는 파이프를 통해서 넘겨받을 수 있다.
-b -h -f -p 1 # 모두 사용자 정의로 가능하다.
21. selects
다음과 같은 배열을 선언한다.
movies=("Avengers" "Matrix" "Titanic")
---
PS3라는 변수를 생성한다.
PS3="Please select your favorite moive: "
---
select문은 for문이랑 매우 유사하다.
select movie in ${movies[@]}
> do
> echo "$movie selected"
> done
1) Avengers
2) Matrix
3) Titanic
Please select your favorite moive: 1
Avengers selected
사용자에게 메뉴를 출력하고, 메뉴를 선택 받는다.
---
이번엔 마지막 배열에 "None"을 추가했다.
movies=("Avengers" "Matirx" "Titanic", "None")
PS3="Please select your favorite moive: "
추가로 case문을 사용하여 None을 선택하면 break을 추가할 수 있다.
select moive in ${movies[@]}
do
case $movie in
"None") echo " My favorite moive is not on the list. quit";break;;
*) echo "$movie selected";;
esac
done
아.....값이 제대로 안나온다..
→ 02. 03일 발견.. moive라고 오타가 났었다.... ㅋㅋ
내일 해결 해야겠다.. 넘 피곤혀..
다시 해보니 또 잘된다..
select movie in ${movies[@]}
> do
> case $movie in
> "None") echo "My Favorite moive is not on the list. quit";break;;
> *) echo "$movie selected";;
> esac
> done
1) Avengers
2) Matirx
3) Titanic,
4) None
Please select your favorite moive: 1
Avengers selected
Please select your favorite moive: 2
Matirx selected
Please select your favorite moive: 3
Titanic, selected
Please select your favorite moive: 4
My Favorite moive is not on the list. quit
감사합니다.
'Cloud > Linux' 카테고리의 다른 글
shell script master -7- (0) | 2022.01.27 |
---|---|
shell script master -6- (0) | 2022.01.27 |
shell script master -4- (0) | 2022.01.13 |
i-node 실습 (0) | 2022.01.12 |
shell script master -3- (0) | 2022.01.05 |