Shell Script I/O

식빵·2022년 2월 27일
0

Shell Script

목록 보기
3/5
post-thumbnail

📌 변수의 종류

  • 환경 변수
    • 모든 쉘들이 필요한 변수이며 이미 지정된 값들이 존재
    • HOSTNAME, USER, UID, PATH 등이 있음
    • 관례적으로 대문자로 변수명을 줘서 다른 일반 변수와 차별성을 둠
    • 부모 쉘이 자식 쉘에게 상속하여, 자식 쉘에서 같은 값(복사본) 사용 가능
    • 사용자가 새로운 환경변수를 만들기 위해서는 export 키워드 사용
    • printenv 를 통해서 확인 가능

  • 특수 변수
    • $0 : 실행된 쉘 스크립트의 명칭
    • $# : 인자의 개수
    • $$ : 현재 PID
    • $1 ~ $n : 넘겨진 인자들
    • $*, $@ : 전달된 인자들을 하나의 문자열로 받은 것

  • 쉘 변수
    • 사용자가 쉘 또는 스크립트에 정의한 변수
    • 서로 다른 쉘간에서 접근할 수 없다. 하나의 쉘에 종속된 변수
    • 서브 쉘( ex: ( 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




📌 Shell expansion으로 값 할당

스크립트 작성

#!/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




📌 read로 입력 받기

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




📌 Child Process & Subshell

이 내용은 쉘 스크립트를 가볍게 짤 목적이라면 필수로 봐야할 내용은 아닙니다!
만약 설명이 좀 난해하다 싶으면 아래 링크 중 위에 2개만 봐도 괜찮습니다.

조금 심화해서 애초에 왜 이렇게 다른지에 대한 깊은 내용을 알고 싶다면 아래 링크를 보시면 됩니다.

저는 지금도 계속 보는 중입니다... 어렵네요 😂


1. (Bash) Child 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 사이에서 환경변수의 상속에 대한 것만 예외적으로 생각하자.



2. SubShell

지금까지 child process를 집중적으로 설명했다.
하지만 이와 비슷하면서 다른 subshell이라는 개념이 있다.
subshell 도 결국은 parent process에서 생성된 child process이기는 하다.
다만 약간의 차이점이 있다.
그건 바로 ( ) $( ) | & 를 이용하여 명령을 실행시킬 때 생성되는 shell이라는 점이다.

subShellchild process와 달리 export 한 변수 뿐만 아니라,
일반적인 쉘 변수, PID, 디렉토리 경로 등 Parent processBash에 있는
모든 정보를 똑같이 복사해서 사용한다.

하지만 subShellChild Process 마찬가지로 Parent Process에서 돌고 있는 Bash에는 영향을 주지 않는다.




✨ 참고



리눅스 시작한지 얼마 안되서 조금 엉성합니다.
틀린 부분있으면 댓글 부탁드려요~

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글