export
키워드 사용printenv
를 통해서 확인 가능$0
: 실행된 쉘 스크립트의 명칭$#
: 인자의 개수$$
: 현재 PID$1 ~ $n
: 넘겨진 인자들$*
, $@
: 전달된 인자들을 하나의 문자열로 받은 것( echo wow )
) 에서는 공유하여 사용 가능var=value
또는 set var=value
=
의 양쪽은 붙여 쓴다. declare
를 사용Associative array
타입 변수의 경우에는 declare
가 반드시 필요참고:
declare
키워드를 통한 변수 타입지정 및 제한하기
변수 값 사용: $var
, ${var}
변수 삭제 : unset var
간단하게 실습해보자.
스크립트 작성
#!/bin/bash
var0=something
echo $var0
echo ${var0}
echo "$var0"
echo "${var0}"
echo "\$var0"
unset var0
echo $var0
실행 결과
[dailycode@myComp:lab]$ ./b.sh
something
something
something
something
$var0
[dailycode@myComp:lab]$
그런데 Array 타입의 경우에는 일반적인 변수 할당 및 사용법이 다르다.
다음 실습을 통해서 몸으로 익히자.
스크립트 작성
#!/bin/bash
## index Array
arr=(1 3 4 5 6)
# echo ${arr} # == ${arr[0]}
echo "all indexes: " ${!arr[@]}
echo "all data: " ${arr[*]}
echo "index=1 data: " ${arr[1]}
unset arr[0] # remove first index data
echo ${arr[*]} # show all
# Associative array , 사실상 java의 Map 과 같다. kev-value 형식.
declare -A fruit_price
fruit_price[apple]="500"
fruit_price[banana]="400"
fruit_price[orange]="800"
echo ${!fruit_price[@]}
echo ${fruit_price[@]}
실행 결과
[dailycode@myComp:lab]$ ./a.sh
all indexes: 0 1 2 3 4
all data: 1 3 4 5 6
index=1 data: 3
3 4 5 6
orange banana apple
800 400 500
스크립트 작성
#!/bin/bash
## parameter expansion
talk="hello, i am from korea"
echo -e "\n============== Starting Parameter Expansion Test!! =============\n"
echo "character count: " ${#talk}
echo "pattern matching (cutting off before ',') : " ${talk#*,}
echo "pattern matching (replace korea to usa) : " ${talk//korea/USA}
echo "cut off at specific index, index+length (0, 0+5) : " ${talk:0:5}
echo "capital String : " ${talk^^}
echo "small String : " ${talk,,}
## command substitution
echo -e "\n\n============= Starting Command Subsitution Test!! ==============\n"
echo "what is today's date? " $(date +%Y/%m/%d)
## string selection
echo -e "\n\n========= String selection Test!!! ==========\n"
myPath=/home/dailycode/lab:/home/dailycode/Download
IFS=:
echo $myPath
IFS=
echo $myPath | cut -f1 -d':'
출력
[dailycode@myComp:lab]$ ./b.sh
============== Starting Parameter Expansion Test!! =============
character count: 22
pattern matching (cutting off before ',') : i am from korea
pattern matching (replace korea to usa) : hello, i am from USA
cut off at specific index, index+length (0, 0+5) : hello
capital String : HELLO, I AM FROM KOREA
small String : hello, i am from korea
============= Starting Command Subsitution Test!! ==============
what is today's date? 2022/02/27
========= String selection Test!!! ==========
/home/dailycode/lab /home/dailycode/Download
/home/dailycode/lab
built-in
명령어인 read
를 쓰면 입력을 받고 변수에 값을 할당할 수 있다.
기본 사용법은 read var
이다.
이러면 스크립트의 진행이 멈추고 사용자 입력을 기다린다.
read 는 딱 하나의 라인만 읽으니 멀티 라인을 주지말자.
스크립트 작성
#!/bin/bash
echo -n "What is your name? "
read name
echo $name
read -p "do you know kimchi? " doKnow
echo $doKnow
read -p "write anything : " # 변수명을 주지 않으면 $REPLY에 저장된다.
echo $REPLY
read -s -p "write your password: " pw # 입력할 때 화면에 보이지 않는다!
echo $pw
출력
What is your name? dailyCode
dailyCode
do you know kimchi? YES
YES
write anything : blablablabla~
blablablabla~
write your password: 1234
참고: read 를 통해서 position parameter 변경하기
아래처럼 하면 position parameter (ex:
$1
) 을 초기화(혹은 덮어쓰기)할 수 있다.
스크립트
#!/bin/bash echo $1 $2 $3 $4 $5 read nums <<< "1 2 3 4 5" set $nums echo $1 $2 $3 $4 $5
출력
[dailycode@myComp:lab]$ ./d.sh a b c d e a b c d e 1 2 3 4 5
이 내용은 쉘 스크립트를 가볍게 짤 목적이라면 필수로 봐야할 내용은 아닙니다!
만약 설명이 좀 난해하다 싶으면 아래 링크 중 위에 2개만 봐도 괜찮습니다.
- https://mug896.github.io/bash-shell/subshells.html (강추)
- https://jitpaul.blog/2018/09/16/shell-scripting-sub-shell-vs-sub-process/
조금 심화해서 애초에 왜 이렇게 다른지에 대한 깊은 내용을 알고 싶다면 아래 링크를 보시면 됩니다.
저는 지금도 계속 보는 중입니다... 어렵네요 😂
이전에 설명했지만, 외부 명령어은 fork & exec
동작을 함으로써
새로운 child process
를 생성하고, 거기서 명령어가 실행되는 것이라고 했다.
이때 명령어를 수행한 shell parent process
와 이로 인해 생긴 child process
는 서로 독립된 공간을 갖고 있어서, 서로의 변수에 접근이 안된다.
예를 들어서 우리가 shell parent process
에서 하나의 변수를 생성하고 child process
에서 그 변수에 변경을 시도하면 과연 될까?
[dailycode@myComp:~]$ hello="hello world!" # shell parent process 변수 생성
[dailycode@myComp:~]$ echo $hello
hello world!
[dailycode@myComp:~]$ bash # child process 생성
[dailycode@myComp:~]$ ps -f
UID PID PPID C STIME TTY TIME CMD
dailyco+ 4829 4828 0 18:03 pts/0 00:00:00 -bash # shell parent process
dailyco+ 4850 4829 0 18:03 pts/0 00:00:00 bash # child process
dailyco+ 4857 4850 0 18:03 pts/0 00:00:00 ps -f
[dailycode@myComp:~]$ echo $hello
[dailycode@myComp:~]$ # 아무것도 출력되지 않는다.
[dailycode@myComp:~]$ hello="good day" # child process에서 같은 이름의 변수에 값 할당
[dailycode@myComp:~]$ echo $hello
good day
[dailycode@myComp:~]$ exit # parent process 에 복귀
exit
[dailycode@myComp:~]$ echo $hello
hello world! # 기존에 parent process에서 사용하던 값을 사용. 영향을 받지 않는 걸 확인.
서로 영향을 안 받고 있다!
그런데 환경변수는 일반 변수와 약간의 차이가 있다.
환경 변수도 결국은 위처럼 서로 영향을 주지 않는 것이 기본 동작이다.
하지만! 처음에 child process
가 생성될 때, parent process
의 "환경변수 복사본"이 만들어져서 child process
에 넘겨진다. (이걸 상속이라고 부르기도 했던 거 같다)
그래서 parent process
의 환경 변수에 어떤 변경사항을 주고나서 "복사본"을 만들면
child process
는 그 값들을 그대로 사용하게 된다.
하지만 이후에는 일반 변수와 마찬가지로 환경변수도 서로 영향을 받지 않는다.
이해가 안 간다면 아래 테스트를 통해서 이해하자.
[dailycode@myComp:~]$ export something=good # parent process에서 환경변수 추가
[dailycode@myComp:~]$ bash # child process 생성
[dailycode@myComp:~]$ echo ${something} # 환경변수가 상속된 것을 확인!
good
[dailycode@myComp:~]$ export god=damn # child process 에서 환경변수를 생성하면?
[dailycode@myComp:~]$ something=changed! # 그리고 기존 환경 변수를 변경하면?
[dailycode@myComp:~]$ echo $something
changed!
[dailycode@myComp:~]$ exit # parent process로 복귀해서 확인해보기
exit
[dailycode@myComp:~]$ echo $something
good # 기존 parent process의 환경변수 값을 유지함.
[dailycode@myComp:~]$ echo $god
[dailycode@myComp:~]$ # 서로 독립적이여서 영향을 안 받는 것을 확인함!
앞으로는 서로 다른 process는 서로 영향을 주지 않는다는 베이스를 깔고,
부모/자식 process 사이에서 환경변수의 상속에 대한 것만 예외적으로 생각하자.
지금까지 child process
를 집중적으로 설명했다.
하지만 이와 비슷하면서 다른 subshell
이라는 개념이 있다.
subshell 도 결국은 parent process
에서 생성된 child process
이기는 하다.
다만 약간의 차이점이 있다.
그건 바로 ( )
$( )
|
&
를 이용하여 명령을 실행시킬 때 생성되는 shell이라는 점이다.
이 subShell
은 child process
와 달리 export
한 변수 뿐만 아니라,
일반적인 쉘 변수, PID
, 디렉토리 경로 등 Parent process
의 Bash
에 있는
모든 정보를 똑같이 복사해서 사용한다.
하지만 subShell
도 Child Process
마찬가지로 Parent Process
에서 돌고 있는 Bash에는 영향을 주지 않는다.
리눅스 시작한지 얼마 안되서 조금 엉성합니다.
틀린 부분있으면 댓글 부탁드려요~