섹션 7. 입출력과 환경변수

 

리눅스 서버를 자동화하여 관리하기 위한 쉘 스크립트(Shell Script) 심화 강좌를 정리합니다.
출처 : inflearn

1. 입력과 출력(Input and Output)

Bash 스크립트의 입력 및 출력은 복잡한 주제입니다.

Bash 스크립트 입력은 다음처럼 다양한 방법이 가능합니다.

1. 명령 줄 인수
2. 환경 변수
3. 파일
4. 파일 기술자(file descriptor)로 표현 가능한 파이프, 터미널, 소켓 등

Bash 스크립트의 출력은 다음처럼 다양한 형식이 가능합니다.

1. 파일
2. 파일 디스크립터로 표현 가능한 다른 것
3. 다른 프로그램에 명령 줄 인수로
4. 혹은 다른 프로그램에 환경 변수의 형태로 넘길 수도

2. 위치 매개 변수

$1,$2,$3 …${10},${11} 에 위치 매개 변수라는 용어를 사용함.

#!/bin/bash
# rename.sh

# 확장자 변경의 예
for name in *.$1
do
 mv $name ${name%$1}$2
done
AWS_TEST:/home/shkim/edu/shell_cmd/images$ ls
Balloon.jpg  Candy.jpg  drill  glob.gif  settings_down.png  settings_up.png  shadingimage.tiff  smaller.tiff
AWS_TEST:/home/shkim/edu/shell_cmd/images$ ../rename.sh png JPG


AWS_TEST:/home/shkim/edu/shell_cmd/images$ ls
Balloon.jpg  Candy.jpg  drill  glob.gif  settings_down.JPG  settings_up.JPG  shadingimage.tiff  smaller.tiff

3. 환경변수와 export

로그아웃 후 재접속 하여 date 명령을 치면 환경변수는 원상복귀 됨.

AWS_TEST:/home/shkim$ date
Wed May  4 00:46:11 KST 2022

AWS_TEST:/home/shkim$ LANG=ko_KR.UTF-8 date
2022. 05. 04. () 00:46:26 KST
AWS_TEST:/home/shkim$ date
Wed May  4 00:46:30 KST 2022

AWS_TEST:/home/shkim$ echo $LANG
en_US.UTF-8
AWS_TEST:/home/shkim$ LANG=ko_KR.UTF-8 #환경변수 지정
AWS_TEST:/home/shkim$ date
2022. 05. 04. () 00:47:30 KST

bash 자식 프로세스에게 기존 환경변수값이 상속됨.

AWS_TEST:/home/shkim$ echo $LANG
ko_KR.UTF-8
AWS_TEST:/home/shkim$ bash
AWS_TEST:/home/shkim$ echo $LANG
ko_KR.UTF-8
#!/bin/bash
echo $LANG in locale.sh

스크립트 내에서도 locale 값이 유지 됨

AWS_TEST:/home/shkim$ ./locale.sh 
ko_KR.UTF-8 in locale.sh

# subshell 에서도 유효함
AWS_TEST:/home/shkim$ echo $LANG; ( echo $LANG in subshell; ); echo $LANG
ko_KR.UTF-8
ko_KR.UTF-8 in subshell
ko_KR.UTF-8
AWS_TEST:/home/shkim$ LANG1=ko_KR.UTF-8

# locale.sh
#!/bin/bash
echo $LANG1 in locale.sh # 수정

# 일반변수 LANG1 에서는 상속이 일어나지 않음
AWS_TEST:/home/shkim$ ./locale.sh 
in locale.sh
# 일반변수에서의 LANG1 은 서브쉘에서 유효함
AWS_TEST:/home/shkim$ echo $LANG1; ( echo $LANG1 in subshell; ); echo $LANG1
ko_KR.UTF-8
ko_KR.UTF-8 in subshell
ko_KR.UTF-8
# 일반변수의 LANG1을 유효하게 하려면 export 를 사용하면 됨.
AWS_TEST:/home/shkim$ export LANG1=ko_KR.UTF-8
AWS_TEST:/home/shkim$ ./locale.sh 
ko_KR.UTF-8 in locale.sh

결론 export 된 변수는 환경변수이다.

4. 변수의 범위(스코프)

쉘 변수는 기본적으로 전역변수(광역변수)라는 점을 확인

# 함수바깥에서 선언된 변수가 함수 내에서 접근이 되는지를 확인
AWS_TEST:/home/shkim$ year=2020
AWS_TEST:/home/shkim$ function sub(){ echo year=${year}} in function; };sub
year=2020 in fuction

AWS_TEST:/home/shkim$ function sub(){ echo year=${year}} in function; year=4050;};sub; echo year=${year} in outer
year=2020 in function
year=4050 in outer

AWS_TEST:/home/shkim$ echo 'echo year=$year' > mydate.sh
AWS_TEST:/home/shkim$ chmod +x mydate.sh
# 스크립트 바깥에서 선언된 변수가 스크립트 내에서 접근이 되는지를 확인
AWS_TEST:/home/shkim$ ./mydate.sh; echo year=$year in outer
year=
year=4050 in outer

# 스크립트 수정
AWS_TEST:/home/shkim$ vi mydate.sh
echo year=$year
year=9999

# 스크립트 내에 변수선언 내용은 스크립트 내부에서만 유효함. 
# 쉘스크립트는 기본적으로 변수에 관한한 sandbox로 이해
AWS_TEST:/home/shkim$ ./mydate.sh; echo year=$year in outer
year=
year=4050 in outer
# 서브쉘 바깥에서 선언된 변수가 서브쉘 내에서 접근이 되는지를 확인
AWS_TEST:/home/shkim$ year=2020;( echo year=${year} in inline; year=4050); echo year=${year} in outer
year=2020 in inline
year=2020 in outer
# 서브쉘 내에서 복제가 되서 실제로 상속효과가 일어남
# 서브쉘은 기본적으로 변수를 복제하여 사용하는 특성으로 이해하자.
# 인라인 바깥에서 선언된 변수가 인라인 내에서 접근이 되는지를 확인
# 인라인 그룹 {} 뒤에는 항상 ; 을 잊지 말자.
AWS_TEST:/home/shkim$ year=2020;{ echo year=${year} in inline; year=4050;}; echo year=${year} in outer
year=2020 in inline
year=4050 in outer
# 인라인 그룹은 기본적으로 명령어를 묶어놓은 것 뿐이다.
# export 한 변수, 위에서 보면 mydate.sh 안 year 변수에는 9999가 선언되있음.
AWS_TEST:/home/shkim$ export year=2020; ./mydate.sh; echo year=$year in outer
year=2020
year=2020 in outer
# 쉘스크립트는 기본적으로 변수에 관한한 sandbox로 이해

5. 파일 디스크립터

파일 디스크립터(FD : File Descriptors)는 프로그램이 파일을 참조하거나, 파일(파이프, 장치, 소켓 또는 터미널)처럼 작동하는 다른 리소스를 참조하는 방법입니다. FD는 데이터 소스에 대한 포인터와 비슷하거나, 혹은 기록 가능한 장소 같은 것입니다. FD에서 읽거나 쓸 때 FD의 리소스에서 데이터를 읽거나 쓰게 됩니다.

  • 표준 입력(Stdin) : 파일 디스크립터 0
  • 표준 출력(Stdout) : 파일 디스크립터 1
  • 표준 오류(Stderr) : 파일 디스크립터 2
# Stdout
AWS_TEST:/home/shkim$ echo hello world
hello world

# Stderr
AWS_TEST:/home/shkim$ ls dir333333
ls: dir33333에 접근할 수 없습니다 : 그런 파일이나 디렉터리가 없습니다

# Stdin
AWS_TEST:/home/shkim$ read -p "key press"
key press

6. 리다이렉션

# 표준출력
AWS_TEST:/home/shkim$ echo "The seagull that flies the highest sees the farthest" > seagull.txt
AWS_TEST:/home/shkim$ cat seagull.txt
The seagull that flies the highest sees the farthest

# 표준출력
AWS_TEST:/home/shkim$ echo "The seagull that flies the highest sees the farthest" 1> seagull.txt
# 표준 에러
AWS_TEST:/home/shkim$ ls dir3333
ls: cannot access dir3333: No such file or directory

AWS_TEST:/home/shkim$ ls dir3333 2> err.log # overwrite 파일이 있을 경우 덮어씀
AWS_TEST:/home/shkim$ cat err.log
ls: cannot access dir3333: No such file or directory

# append : >> 기존 파일에 추가
AWS_TEST:/home/shkim$ ls dir4444 2>> err.log
AWS_TEST:/home/shkim$ cat err.log
ls: cannot access dir3333: No such file or directory
ls: cannot access dir4444: No such file or directory
AWS_TEST:/home/shkim$ echo ABCD > file1
AWS_TEST:/home/shkim$ echo 1234 > file2
AWS_TEST:/home/shkim$ cat file1 file2 > file # 2개의 파일이 결합됨.
AWS_TEST:/home/shkim$ cat file
ABCD
1234
AWS_TEST:/home/shkim$ while read v; do echo $v; done<file #input 파일을 입력 받음
ABCD
1234

# 표준 출력장치로 나온 메시지가 방향을 틀어 steven.txt로 들어가고
# 표준 에러로 출력될 메시지 또한 표준출력으로 방향이 변경되었으며 사실상 모든 메시지는 steven.txt에 남게된다.
AWS_TEST:/home/shkim$ echo "Jurassic World" > steven.txt 2>&1

# lucas.txt 파일은 발견되지 않는다.
# 표준 출력장치가 아닌 표준에러로 에러메시지가 나올 것이었지만 에러메시지는 리다이렉트로 인해 표준에러가 아닌 표준출력으로 에레메시지가 출력됨.
AWS_TEST:/home/shkim$ grep -i "Star Wars" steven.txt lucas.txt 2>&1
grep: lucas.txt: No such file or directory
AWS_TEST:/home/shkim$ echo $?
2