본문 바로가기

Tools and Utilities/Linux

[Shell Script 실습] Ch2. 따옴표와 변수 설정(Quote and Variable)

오픈 소스 비영리 기관 'Open Source Initiative'의 로고.   https://opensource.org/

본 글은 학교 '오픈소스 소프트웨어 입문' 과목을 수강하며 실습(또는 공부)한 내용을 정리한 글입니다.

개인 기록 용도로 작성한 글이라, 직접 이 글을 보고 실습을 따라하기엔 어려움이 많을 것으로 예상됩니다.
혹시 본 글을 보며 Linux를 공부하실 목적이라면, 일단 키워드 위주로 AI에게 물어봐가면서, 본인의 Linux 터미널에서 직접 타이핑해가며 공부하시기를 추천드립니다.

질문이나 의견이 있다면 자유롭게 댓글 달아주세요!

 

# Bash syntax overview
기본적인 문법들을 배워 보자.
### 특수문자들
"#"는 주석

&는 백그라운드 잡

|는 파이프. |&로 쓰면 stderr도.

""''. -> 나중에 배움. '은 null expansion이라 함.
!중간고사! -> 각각 "랑 '을 쓴 걸 두고 실행 출력 결과 쓰라 함.

` -> 백코트. 

() {;} 괄호로 쉘을 여러 개 묶을 수 있음.

array는 []

이걸 숫자로 계산해주세요 -> (( ))

조건은 [[]]

조건부 실행은 && ||

변수는 $ & / -> $0 $1 $2 $3같은 것도 씀. argument 전달하는 용도, c언어 argv 느낌.

history - ! !! 느낌표

redirection - >  &>  0<  1>  2>  >>  <<  <<<  # <<< is bash only 
우리 이미 리다이렉션은 리눅스에서 다 배웠음.

pattern (globbing) - * ?  # extended pattern [...], !(p)  *(p) +(p) @(p)

# Lecture 02: Quote and Variable
# Quote Overview
만약 우리가 name=123 했으면, 1 2 3 문자로 이루어진 문자열이 들어가는 거임. 정수 123이 아님.

! 중간고사 !
#! /usr/bin/bash
NAME=$1
echo "Hello $NAME!"
echo ARGS "0: " $0 "1: " $1 "2: " $2 "3: " $3

이렇게 hello.sh 바꾸고,

foss110@ajousw:~/lab0403$source hello.sh Yeonwoo
Hello Yeonwoo!
ARGS 0:  -bash 1:  Yeonwoo 2:  3:

foss110@ajousw:~/lab0403$ source hello.sh Yeonwoo Lee
Hello Yeonwoo!
ARGS 0:  -bash 1:  Yeonwoo 2:  Lee 3:

foss110@ajousw:~/lab0403$source hello.sh "Yeonwoo Lee"
Hello Yeonwoo Lee!
ARGS 0:  -bash 1:  Yeonwoo Lee 2:  3:

공백으로 나뉜다는 걸 볼 수 있음.

여기서, 여담이지만 hello.sh 안에서 NAME이 재할당되고 있는 걸 볼 수 있음.
그래서 
foss110@ajousw:~/lab0403$ source hello.sh $NAME
Hello Yeonwoo!
ARGS 0:  -bash 1:  Yeonwoo 2:  Lee 3:
foss110@ajousw:~/lab0403$ echo "$NAME"
Yeonwoo
foss110@ajousw:~/lab0403$ NAME="Yeonwoo Lee"
foss110@ajousw:~/lab0403$ source hello.sh "$NAME"
Hello Yeonwoo Lee!
ARGS 0:  -bash 1:  Yeonwoo Lee 2:  3:

중요한 건, $NAME"$NAME"도 차이가 있다.
""가 없으면, 공백이 있을 시 쉘이 $NAME을 여러 개의 인자로 분리해서 처리함.
""가 있으면 공백 있어도 쉘이 하나의 인자 통쨰로 봄.

' '는 no expansion이라 했음.
expansion을 안 하면, $NAME이 직접 그대로 들어감. 
내가 $NAME 그 자체가 필요할 수 있잖음. 그럴 때 쓰는 거.

foss110@ajousw:~/lab0403$ source hello.sh '$NAME'
Hello $NAME!
ARGS 0:  -bash 1:  $NAME 2:  3:
이렇게.

---

mkdir lab0408
cp ../**/hello.sh .

vi hello.sh
좀 수정할 거임.

#! /usr/bin/bash
ps -l
echo "Hello $NAME!"
echo ARGS "0: " $0 "1: " $1 "2: " $2 "3: " $3

foss110@ajousw:~/lab0408$ . hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 R  3110  176520  163955  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello !
ARGS 0:  -bash 1:  2:  3:

-> ps -l 결과가 bash밖에 없다.
즉, hello.sh를 서브 쉘에서 실행한 게 아니라,
현재 쉘에서 실행한 것임.

NAME=LEE
foss110@ajousw:~/lab0408$ bash hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  179772  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 bash
0 R  3110  179773  179772  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello !
ARGS 0:  hello.sh 1:  2:  3:

-> 보면, NAME 설정한 게 사라짐!!
즉, 원래 쉘에서 설정한 게 사라진다.
그리고 배쉬가 하나 더 열림. 즉, 서브쉘에서 실행됨.

서브쉘에서도 저 변수 NAME을 쓰고 싶으면, export 명령어를 써야 함.
foss110@ajousw:~/lab0408$ export NAME
foss110@ajousw:~/lab0408$ bash hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  183303  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 bash
0 R  3110  183304  183303  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello LEE!
ARGS 0:  hello.sh 1:  2:  3:

참고) 저거 bash만 한 다음 . hello.sh해도 동일.
bash만 한 다음 . hello.sh하면, 그 쉘에서 여전히 다른 명령어 실행 가능.

bash만 한 상태에서, 이번엔 서브 쉘에 NAME가 왔다.
그러면, 테스트해보자. NAME을 서브 쉘에서 바꿔보자.

foss110@ajousw:~/lab0408$ NAME=KIM
foss110@ajousw:~/lab0408$ . hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  184070  163955  0  80   0 -  2066 do_wai pts/76   00:00:00 bash
0 R  3110  184283  184070  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello KIM!
ARGS 0:  bash 1:  2:  3:
foss110@ajousw:~/lab0408$ exit
exit
foss110@ajousw:~/lab0408$ . hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 R  3110  184371  163955  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello LEE!
ARGS 0:  -bash 1:  2:  3:

보면, 서브 쉘에서 바꾼 변수는 원래 쉘에서는 적용되지 않는 걸 볼 수 있음.


foss110@ajousw:~/lab0408$ bash hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  187147  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 bash
0 R  3110  187148  187147  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello LEE!
ARGS 0:  hello.sh 1:  2:  3:

-> export NAME을 해줬기 때문에 LEE이 나온 거임.
그러면, export 취소는?
-> -n 인자 주면 됨.
export -n NAME

! 중간고사 !
이 상황에서 bash hello.sh 실행 결과는?
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  188556  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 bash
0 R  3110  188557  188556  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello !
ARGS 0:  hello.sh 1:  2:  3:
unexport해줬으니까 당연히 NAME이 안 뜨지.


chmod 755 hello.sh -> 파일을 실행 파일로 만드는 명령어, 그냥 외워도 될듯.
권한을 rwxr-xr-x로 만들어줌.

이제 ./hello.sh로 실행 가능(뭐 원래도 권한상 되긴 했지만)

foss110@ajousw:~/lab0408$ ./hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  190249  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 hello.sh
0 R  3110  190250  190249  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello !
ARGS 0:  ./hello.sh 1:  2:  3:

보면, 아까 bash랑 달리, hello.sh가 실행됐고,
LEE도 안 갔음. 왜냐면 unexport해줬으니까.
얘도 그 서브쉘 이름이 쉘 스크립트 파일 이름일 뿐, 새로운 서브쉘이 실행된 건 맞으니까.
근데 다시 export해주면 얘도 당연히 NAME 들어감.

foss110@ajousw:~/lab0408$export NAME
foss110@ajousw:~/lab0408$ !.
./hello.sh
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  3110  163955  163952  0  80   0 -  2103 do_wai pts/76   00:00:00 bash
0 S  3110  191571  163955  0  80   0 -  1723 do_wai pts/76   00:00:00 hello.sh
0 R  3110  191572  191571  0  80   0 -  2202 -      pts/76   00:00:00 ps
Hello LEE!
ARGS 0:  ./hello.sh 1:  2:  3:

! 중간고사 !
교수가 위에 저거 중간고사 낸다고 함.
즉, export 여부에 따른 bash랑 그냥 실행 각각 어케 되는지.


---
# 다시 bash syntax overview 복습

! 중간고사 !
저거 "" 말고 ''은 no expansion인거 시험에 냄!!
echo '$NAME' -> $NAME이 출력됨.
foss110@ajousw:~/lab0408$ echo $NAME
LEE
foss110@ajousw:~/lab0408$ echo "$NAME"
LEE
foss110@ajousw:~/lab0408$ echo '$NAME'
$NAME

저거`` quote는 문자열로 만드는 거다 결과를. 

괄호는 괄호를 열고 저렇게 하면, 서브 쉘에서 저 프로그램이 돈다.
그리고 { ;}는 여러 프로그램을 실행시킨다. 그런 느낌 일단은.

[]의 경우는, 이 안에 있는 애들을 막 계산해서 출력을 내주는데, 출력 값은 또 string임.

[[]]는 조건문.

history는 내가 이전에 입력한 명령어들 기록.