Run The Bridge

shell script master -7- 본문

Cloud/Linux

shell script master -7-

anfrhrl5555 2022. 1. 27. 00:38
728x90

0. 입력과 출력

bash의 입력

- 명령 줄 인수

- 환경 변수

- 파일

- 파일 기술자(file descriptor)로 표현 가능한 파이프, 터미널, 소켓 등

 

bash의 출력

- 파일

- 파일 디스크립터로 표현 가능한 다른 것

- 다른 프로그램에 명령 줄 인수로

- 혹은 다른 프로그램에 환경 변수의 형태로 넘길 수도


1. 위치 매개 변수

다음과 같은 이미지 파일들이 존재한다.

-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

---

이 image 파일들 중 확장자가. png 인 것을. JPG로 바꿔보자.

#!/bin/bash

for name in *.$1
do
 mv $name ${name%$1}$2
done

예전에 파일들을 ls 해서 입력할 때 $(ls -l)이 아니고 그냥 *.*를 하면 입력이 되었던 것처럼 특별한 인용부호는 써주지 않는다.

 

$1에는. png라는 값이 들어갈 것이고, 

 

$name에는 png확장자를 가지는, 즉 settings_up, down.png가 들어간다.

 

$[name%$1}은 예전에 배웠듯이 뒤에서부터 $1을 찾아 제거하고, $2를 붙이는 명령어이다.

아래 블로그 위치에서 Ctrl+F를 누르고 'teststring'를 검색하면 예시가 잘 나와있다.

https://anfrhrl5555.tistory.com/166

 

shell script master -3-

0. 쉘 스크립트란 무엇인가? 쉘(shell)은 명령 인터프리터로 사용자가 O/S에 대화식(interactively)으로 명령을 내리거나, 명령을 일괄(batch)적으로 실행할 수 있는 기능을 제공하는 응용 프로그램 Kernel

anfrhrl5555.tistory.com

※ 추가로 위치 매개 변수가 $9를 넘어 10이 되면 $10이 아니고, ${10}처럼 표현해주어야 한다.


2. 환경변수와 export

locale -a  # 지역별 언어 패키지를 확인할 수 있다.

---

date 명령어를 사용했을 때, 한국어가 나오게 만들어 본다.

LANG=ko_KR.UTF-8 date  # 1회성 
2022. 02. 06. (일) 23:34:29 KST

---

다음과 같이 입력한다.

LANG=ko_KR.UTF-8
echo $LANG
ko_KR.UTF-8

---

date
2022. 02. 06. (일) 23:35:46 KST

하지만 reboot시, 원래의 en_US.UTF-8로 돌아온다.

---

간단하게 스크립트 파일을 작성해서 항상 ko_KR를 환경변수에 저장해 본다.

#!/bin/bash

echo $LANG in locale.sh

---

subshell에서도 유요 한 지 확인한다.

echo $LANG; ( echo $LANG in subshell: ); echo $LANG
ko_KR.UTF-8
ko_KR.UTF-8 in subshell:
ko_KR.UTF-8

---

다음처럼 환경변수가 아닌, 일반 변수로 LANG1을 만든다.

LANG1=ko_KR.UTF-8
#!/bin/bash

echo $LANG1 in locale.sh

---

LANG1의 값을 확인하고, 스크립트를 실행시켜 준다.

echo $LANG1
ko_KR.UTF-8
./locale.sh
in locale.sh

일반 변수 LANG1에는 실행결과가 다른 것을 알 수 있다. → 즉 상속이 일어나지 않는다.

 

그러면 서브 쉘에서는 어떨까? → 유요 하다.

echo $LANG1; ( echo $LANG1 in subshell: ); echo $LANG1
ko_KR.UTF-8
ko_KR.UTF-8 in subshell:
ko_KR.UTF-8

---

스크립트 파일에서도 LANG1을 유용하게 하는 방법 → export를 사용해준다.

export LANG1=ko_KR.UTF-8
./locale.sh
ko_KR.UTF-8 in locale.sh

---

linux에서 환경변수를 확인하는 'env'명령을 통해 LANG1을 확인한다.

env | grep -i LANG1
LANG1=ko_KR.UTF-8

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

다음의 변수를 선언한다.

year=2020

---

함수를 하나 생성해서, 외부 변수가 함수에도 영향을 미치는지 확인한다.

function sub() { echo year=${year} in function; };sub
year=2020 in function

함수 내부에서도 유요함이 확인되었다.

---

그럼 함수 내부에서 값 변경이 외부에서까지 영향을 미칠까?

function sub(){ echo year=${year} in function; year=4050;};sub ; echo year=${year} in outer
year=2020 in function
year=4050 in outer

함수 안에서 'year=4050'으로 바꾸고 함수 밖에서 출력했을 때, year 값이 바뀌는 것을 확인할 수 있다.

---

echo 'echo year=$year' > mydate.sh
# vi mydate.sh
echo year=$year

---

스크립트 바깥에서 선언된 변수가 스크립트 내에서 접근이 되는지를 확인한다.(될 리가 없지 ㅋㅋ)

./mydate.sh; echo year=$year in outer
year=
year=4050 in outer

---

스크립트 파일을 간단하게 고치고, 스크립트 바깥에서 접근이 되는지를 확인한다.

# vi mydate.sh
echo year=$year
year=9999
./mydate.sh; echo year=$year in outer
year=
year=4050 in outer

안된다.

---

그렇다면 서브 쉘에서의 변수 범위는 어떻게 될까?

year=2020;( echo year=${year} in inline; year=4050; ); echo year=${year} in outer
year=2020 in inline
year=2020 in outer

최초 바깥에서 year=2020으로 year을 초기화시켜주었기 때문에 () 안에서 year은 2020을 담고 있고, inline; 이후에 year를 4050으로 초기화했지만, 서브 쉘에서 변경된 year=4050은 변경되지 않는다

 

그리고 바깥에서 year=2020을 선언해놨기에, 마지막 echo year=${year} 부분에도 2020이 출력되는 것을 알 수 있다.

 

※ 서브 쉘은 기본적으로 변수를 복제하여 사용하는 특성으로 이해하자.

---

그러면 인라인 그룹'{}'으로 바꿔본다면?

ear=2020;{ echo year=${year} in inline; year=4050; }; echo year=${year} in outer
year=2020 in inline
year=4050 in outer

인라인 그룹 안에서 선언된 변수는, 인라인 그룹을 벗어나도 영향을 끼치는 것을 알 수 있다.

 

※ 인라인 그룹은 기본적으로 명령어를 묶어놓은 것뿐, 다른 서브 쉘이 아니기 때문에 가능한 것


export의 범위에 대해서 알아본다.

export year=2020;./mydate.sh; echo year=$year in outer
year=2020
year=2020 in outer
env | grep year
year=2020

아까도 보았듯이, mydate.sh에 존재하는 'year=9999'는 스크립트를 벗어나서는 효과가 없다.

 

우선적으로 export을 통해 상속된 year=2020이 뒤에 나오는 year=$year에 값이 들어간 것을 확인할 수 있다.

 

※ 쉘 스크립트는 기본적으로 변수에 관한 한 sandbox로 이해한다.

 

 

변수와 export에 범위는 한 번에 이해하기 어려워 보인다. 

 

여러 번 봐야 할 듯...


4. 파일 디스크립터

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

---

다음과 같이 echo를 통해 출력하면, 파일 디스크립터 1번 표준 출력 장치를 사용한 것이다.

echo hello world
hello world

즉, echo 명령어는 stdout를 사용한다.

---

이러한 에러 메시지는 표준 오류 출력장치를 통한다.

ls dir3333333333
ls: cannot access dir3333333333: 그런 파일이나 디렉터리가 없습니다

---

다음과 같이 사용자의 입력을 받는 명령어를 사용하면 표준 입력 stdin을 이용한다.

read -p "key press: "
key press: k

5. 리다이렉션(<, <<, >, >>)

다음과 같이 '>'를 사용해서 출력 결과를 프롬프트에 뿌리지 않고, seagull.txt라는 파일에 저장된다.

echo "The seagull that files the highest sess the farthest" > seagull.txt
cat seagull.txt
The seagull that files the highest sess the farthest

---

다음과 같은 파일 디스크립터 stdout을 사용해도 똑같은 결과를 볼 수 있다.

echo "The seagull that files the highest sess the farthest" 1> seagull.txt

---

오류를 나타내는 파일 디스크립터 stderr 2번을 사용한다.

ls dir3333
ls: cannot access dir3333: 그런 파일이나 디렉터리가 없습니다

ls dir333 2> err.log

cat err.log
ls: cannot access dir333: 그런 파일이나 디렉터리가 없습니다

---

'>>'를 두 개 사용하면 append의 뜻을 가지고, '>'는 파일이 없다면 생성되고, 있다면 overwrite 되는 방식이다.

ls dir4444 2>> err.log
cat err.log
ls: cannot access dir333: 그런 파일이나 디렉터리가 없습니다
ls: cannot access dir4444: 그런 파일이나 디렉터리가 없습니다

---

다음의 파일을 생성한다.

echo ABCD > file1
echo 1234 > file2

두 개의 파일을 하나로 병합할 수도 있다.

cat file1 file2 > file
cat file
ABCD
1234

---

read의 내용을 읽어서 파일에 반영한다. '<'는 input으로 파일을 입력받는다.

while read v; do echo $v; done<file
ABCD

1234

---

정상적인 메시지는 steven.txt로 저장된다.

오류 메시지 또한 리다이렉트를 걸어서 표준 에러또한 표준 출력장치인 1번으로 들어간다.

echo "Jurassic Wolrd" > steven.txt 2>&1

사실상으로 모든 메시지는 steven.txt로 저장된다.

 

'2>&1'로 명시하지 않고 '2>1'로 작성하면 '1'이라는 파일이 생성된다.

---

다음의 명령어는 steven.txt라는 파일은 존재하지만 lucas.txt 파일이 존재하지 않아, 에러를 발생시키는데

표준 에러를 표준 출력인 1번으로 리다이렉션 시킨 것이다.

 

즉  '2>&1'가 없어도 같은 결과가 나오지만, 파일 디스크립터를 사용함으로써 컨트롤하기에 유용해 보인다.

grep -i "Star wars" steven.txt lucas.txt 2>&1
grep: lucas.txt: 그런 파일이나 디렉터리가 없습니다
echo $?
2

감사합니다.

728x90

'Cloud > Linux' 카테고리의 다른 글

shell script master -9- (마지막)  (0) 2022.01.27
shell script master -8-  (0) 2022.01.27
shell script master -6-  (0) 2022.01.27
shell script master -5-  (0) 2022.01.21
shell script master -4-  (0) 2022.01.13
Comments