#!bin/bash
#
#정수 2개를 입력 받고 첫 번째로 받은 정수가 홀수라면 서로 더하고
#만약 짝수라면 뺀 값을 출력하는 코드를 어떤 언어든 상관없이
#자신이 사용하는 언어로 최대한 비효율적으로 짜주시면 됩니다.
#

echo "Enter the two integer : "
read first_integer secound_integer
echo "first_integer : $first_integer, secound_integer : $secound_integer"
touch integer.txt
data="./integer.txt"
echo $first_integer >>${data}
echo $secound_integer >>${data}

first_line=$(cat ./integer.txt | head -n 1)
secound_line=$(cat ./integer.txt | tail -n 1)

first_line_integer=$((first_line))
secound_line_integer=$((secound_line))

echo "first var : $first_line_integer"
echo "secound var : $secound_line_integer"

if [ $first_line_integer -eq 0 ]; then
	echo "0 don't div"
fi

div_buf=$first_line_integer
while [ $div_buf -ge 2 ]; do
	div_buf=$(($div_buf - 2))
done
if [ $div_buf -eq 0 ]; then
	printf_buf=$(($first_line_integer + $secound_line_integer))
else
	printf_buf=$(($first_line_integer - $secound_line_integer))

fi

echo "result : $printf_buf"

rm ./integer.txt

인터넷의 명절 만우절이다. 만우절 기념으로 소셜미디어에서 재밌는 제안을 보았다. 두 개의 정수를 받아 홀수 짝수를 판단하고, 덧셈 혹은 뺄셈을 한 뒤에 출력하는 프로그램을 짜는데 최대한 비효율적으로 짜달라는 글을 보았다.

나는 어떻게 할까 고민하다가 쉘스크립트에 펄을 인라인으로 사용해서 짜야겠다고 생각했다. 하지만 생각보다 펄의 문법은 더 난해하고, 원하는 정보가 잘 나오지 않아 그냥 쉘 스크립트만 사용하기로 했다.

해당 쉘스크립트는 데이터를 입력 받아 txt 파일에 쓰고, 다시 그걸 읽어 나머지 연산자 없이 홀수 짝수를 판단하고 출력한 뒤에 txt 파일을 지우는 형태로 쓰여져 있다.

서버 쪽 일을 하면서 종종 쉘스크립트를 보게 된다. 보통 자동화를 하기 위해 많이 쓰는 편인데 예를 들어 일정시간마다 로그 같은 걸 백업하게 한다던지, 아니면 유저를 추가할 때마다 설정 파일에 어떤 데이터를 추가한다던지, 아파치 같은 데몬들을 재부팅 하는 일 등의 반복적인 작업을 자동화할 때 많이 쓴다.

개인적으로 쉘스크립트 중에 가장 인상 깊었던 것은 텔레그램 봇이다. curl 을 이용해 http endpoint에 데이터를 넘겨주는 형식으로 동작하며, crontab 을 통해 일정 주기로 실행된다. 이 봇은 CPU나 메모리 사용량을 모니터링하고, 일정 수치를 넘으면 텔레그램을 통해 알려주는 방식으로 동작한다.

하지만 그러면 궁금한 점이 생긴다. 쉘스크립트의 인터프리터는 무엇인가? 쉘스크립트는 스크립트언어니까 분명 인터프리터가 있을 것이다. 하지만 별도로 설치를 하여 실행한 적은 없다.

왜냐하면 쉘스크립트는 쉘자체가 인터프리터이기 때문이다. bash 쉘이 커널과 통신하는 인터프리터이기 때문에 쉘스크립트는 UNIX 계열의 OS만 설치되어 있으면 보통은 실행이 가능하다.

서버 관리-운영자 입장에서 별도의 프로그램 설치 없이 사용할 수 있다는 장점 때문에 자동화된 작업에 쉘스크립트를 많이 이용한다.

쉘 스크립트는 본디 그런 용도로 만들어졌다. AT&T 벨 연구소에서 유닉스를 만들 당시에 C 언어로 하기엔 간단하고 자동화가 가능한 작업을 하기 위해 쉘 스크립트를 만들었다는 문구를 ‘유닉스의 탄생’ 이라는 책에서 본 적이 있다.

하지만 쉘스크립트는 조금 다른 언어들과 문법이 다르다. 그렇기 때문에 조금 주요하게 쓰이는 부분들을 소개해보고자 한다.

그와 별개로 프로그래밍 언어들을 공부하면서 느낀 것인데 몇 가지 언어들의 문법을 알면 나머지는 문법을 찾아보면서 이해가 가능하다는 점이 신기했다. 그래서 정규 과정으로 쉘스크립트를 배운 적은 없지만 크게 문법을 찾아보면서 이해하고 짜는데 문제는 없었다.

일단 쉘 스크립트는 #!bin/bash 를 제일 위에 사용하여 쉘스크립트임을 선언한다. 유닉스 계열 언어들은 기본적으로 확장자가 없기 때문에 특히 중요하다.

여기에 쓰이는 명령어들은 쉘에 그대로 입력된다고 생각하면 된다. 예를 들어 내가 비어 있는 파일을 만들고 싶으면 touch a 이런 식으로 그냥 쓰면 된다.

조금 특이한 점은 변수를 $ 를 이용해서 사용한다는 점과 조건문에 -eq 같은 것들을 사용한다는 점이다. 자세한 내용은 다음과 같다.

Operator Description Value
! EXPRESSION The EXPRESSION is false.
-n STRING The length of STRING is greater than zero.
-z STRING The lengh of STRING is zero (ie it is empty).
STRING1 == STRING2 STRING1 is equal to STRING2
STRING1 != STRING2 STRING1 is not equal to STRING2
INTEGER1 -eq INTEGER2 INTEGER1 is numerically equal to INTEGER2
INTEGER1 -gt INTEGER2 INTEGER1 is numerically greater than INTEGER2 (>=)
INTEGER1 -lt INTEGER2 INTEGER1 is numerically less than INTEGER2 (<=)
-d FILE FILE exists and is a directory.
-e FILE FILE exists.
-r FILE FILE exists and the read permission is granted.
-s FILE FILE exists and it’s size is greater than zero (ie. it is not empty).
-w FILE FILE exists and the write permission is granted.
-x FILE FILE exists and the execute permission is granted.

if 문의 형식은 다음과 같다.

if [ 조건문 ]
then
    수행문
elif [ 조건문 ]
    수행문
else
    수행문
fi

while 문은 다음과 같다.

while [ 조건문 ]
do
    수행문
done

for 문은 다음과 같다.
```bash
for 인덱스 in 워드1 워드2 --- 워드N
do
  수행문
done

for 문의 특이한 점은 문자도 된다는 점이다!

재밌는 팁 중 하나인데 쉘스크립트는 그 특성상 STRING 을 정수로 변환할 일이 있다. 예제로 올린 쉘에서도 텍스트 파일에 쓴 정수를 다시 읽어서 정수로 연산해야한다. 그럴 때는 다음과 같이 변환하면 된다.

first_line_integer=$((first_line))

아 그리고 특이하게도 대입연산자 좌우에는 공백이 있으면 안 된다. 이를테면 var1 = var2 는 문법상 오류이며 var1=var2 로 써야한다.

앞으로 인프라 쪽 일을 계속 할 것이라서 프로그래밍을 할 일이 얼마나 많은지는 모르겠지만, 쉘스크립트는 지속적으로 쓰이고 유지보수 되고 있어 한번은 배워야겠다고 생각했다.

이번 기회에 이렇게 쉘스크립트를 한번 써먹었으니 다음엔 좀 더 수월하게 할 수 있을 것 같다. 왜 사람들이 언어나 프로그래밍은 직접 사용해야 빨리 늘고, 익히기 훨씬 쉽다고 하는지 이제서야 이해가 되기 시작되고 있고 그게 정말 맞는 것 같다.

아참 해당 만우절 이벤트는 C 언어를 어셈블리처럼 메모리를 직접 불러오고 막 비트연산을 이용해 푸신 분이 최강이었다. 어떻게 동작하는지 조차 이해하지 못했닼ㅋㅋㅋㅋ 세상은 넓고 재야의 고수는 많다라고 느낄 수 밖에 없었다.