본문 바로가기
Study

[Linux] 모던 리눅스 교과서 3장 - 스크립트

by wwns 2024. 11. 17.
반응형

3장에서는 셸과 스크립팅을 다룬다.

 

스크립트는 서버 관리자라면 정말 자주 사용하는 것 같다. (복잡하지 않은 작업들)

  • 분 단위 자원 사용률 기록 / 주기적인 상태 확인
  • 모든 서버들에 대해 파일을 전송해야 할 때
  • 배치 Job 실행하기
  • 서비스 기동, 중지하기
  • 백업

고민했던 스크립트를 생각하면서 내용을 정리해 본다.


  • 터미널
    • 텍스트로 된 사용자 인터페이스를 제공하는 프로그램
    • TERM이라는 환경변수에 사용 중인 터미널 에뮬레이터값이 저장되어 있음 (출력방식)
    • 터미널 내부에서 실행되는 명령 인터프리터 역할을 하는 프로그램
  • 스트림
    • 출력과 입력 시 프로세스 간 데이터를 전달하기 위한 통로
    • 스트림은 FD(파일디스크립터)에 의해 관리됨
      • 0, 1, 2 FD에 표준 입출력 스트림이 예약되어 있음
  • 변수
# 셸 변수 정의 (set으로 확인 가능, env에는 보이지 않음)
$ set myvar=hello
$ set | grep myvar
myvar=hello
$ env | grep myvar
# 출력 없음

# 환경 변수로 변환 (export 후 env에서 보임)
$ export myvar
$ env | grep myvar
myvar=hello

 

 

터미널 셸과 스크립트 셸

 

터미널 환경에서의 설정값과 스크립트 실행 시의 설정값이 달라 예상치 못한 결과가 나타날 수 있어 알아둬야 할 것이 있다.

  • 터미널 셸인터랙티브 셸로 실행
    • 로그인 상태 및 사용자 설정 파일(~/.bashrc, ~/.profile 등)을 로드
  • 스크립트 셸비인터랙티브 셸로 실행됩니다.
    • 사용자 입력 없이 지정된 명령어를 순차적으로 실행
    • 로그인 환경 설정 파일을 로드하지 않으며, 스크립트 자체에서 명시적으로 설정된 환경만 사용

동일한 셸 변수를 유지하고 싶다면

  • 터미널 환경을 시작할 때의 설정파일을 로드하는 명령어를 스크립트 맨 위에 입력
  • 환경 설정용 파일 ex).ini 을 통해 원하는 환경변수를 주입해 줄 수 있음
  • 스크립트 실행 시 source .sh로 실행하면 현재 터미널의 환경변수를 유지할 수 있음

행 탐색과 조작

  • Ctrl + a
    • 행의 시작으로 커서 이동
  • Ctrl + e
    • 행의 마지막으로 커서 이동
  • Shift + g
    • 맨 마지막 행으로 커서 이동
  • Ctrl + b
    • 위 페이지로 이동
  • Ctrl + d
    • 아래 페이지로 이동

 

인간 친화적인 셸

 

책에서 인간친화적인 모던 셸을 추천하고 있다.

대표적인 것은 fish 셸과 zsh 인 것 같다.

 

zsh은 들어보기도 했고, bash shell을 호환한다고 하니 흥미가 좀 생겼지만 실제 회사에서 기본 bash shell이 아닌 다른 쉘들을 서버에 도입하기는 쉽지 않을 것 같다.. 그만한 이유가 있어야 하고 변화는 어디서 장애를 불러올지 모르기에.. 

 

zsh에서 5개의 시작 파일을 사용한다고 나오는데 bash shell도 마찬가지이다. 해당 시작 파일을 통해 계정마다 공통된 환경을 제공할 수 있으며 활용하기 나름이다.

 

나의 경우에는 각 계정별로 명령 History를 저장하기 위해 해당 설정을 해놓았다.

### 계정 접속 시 공통으로 호출되는 profile
ubuntu@ip-172-31-130-226:/etc/skel$ cat /etc/profile
...
HISTTIMEFORMAT="%Y-%m-%d [%H:%M:%S] "
export HISTTIMEFORMAT
export HISTSIZE=5000  # 저장할 히스토리 크기
export HISTFILESIZE=10000  # 저장할 파일 크기
timestamp=$(date +"%Y%m%d_%H%M%S")
export HISTFILE="/home/History/${USER}_history_${timestamp}"

### 계정 생성 시 공통으로 내려지는 bash_logout파일
ubuntu@ip-172-31-130-226:/etc/skel$ cat .bash_logout
history -a > $HISTFILE

 

셸은 사용하기 나름이고 아직까지는 bash shell 말고는 사용해 본 게 없어서 다른 셸을 선뜻 설치하고 테스트해 보는 게 끌리지 않았다..

 

fish shell 설치

https://jungmonster.tistory.com/253

 

[Linux/Tool] 우분투 Fish Shell 사용하기

Ubuntu 17.10 친구가 fish shell을 추천해서 설치 해봤습니다. https://fishshell.com/ fish shell 설치 sudo apt-add-repository ppa: fish-shell/release-2 sudo apt-get update sudo apt-get install fish 쉘 지정 chsh -s /usr/bin/fish 이후 쉘

jungmonster.tistory.com

 

zsh 설치

https://log4cat.tistory.com/7

 

Ubuntu에 Oh My Zsh 설치

# zsh-syntax-highlighting git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting # zsh-autosuggestions git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~

log4cat.tistory.com


tmux - 터미널 멀티플렉서

 

두 개의 창에서 상호의존적인 작업이 필요할 때 다중화를 통해 터미널 사용을 개선하는 방법

터미널 멀티플렉서를 사용해야 하는 이유가 무엇일까 생각해 봤다.

  • ssh 접속 시 TMOUT=0 설정을 통해 터미널이 종료되지 않게 설정해 놓으면 끊기지 않는다?
    • ssh 옵션에 의해 접속 종료될 수 있음
    • 네트워크가 끊기면 접속 종료될 수 있음
      • tmux 사용 시 접속이 끊기더라도 세션이 살아있어 작업환경이 보존된다!
  • 다중 작업이 필요하면 터미널 여러 개 열면 되는 거 아닌가?
    • 언제 끊길지 모르는 것, 어떤 터미널에서 어떤 작업을 하고 있었는지 추적하기 헷갈리는 것

해당 이유만으로도 충분히 tmux를 사용하는 게 좋다고 생각하여 명령어를 연습해 볼 생각이다.!

 

명령어설명 - 커맨드 트리거 - Ctrl+b

새로운 세션 생성 tmux new -s <session_name>
세션 리스트 확인 tmux list-sessions
세션 분리(나오기) Ctrl-b d
세션 다시 연결 tmux attach -t <session_name>
세션 종료 특정 세션 종료
tmux kill-session -t <session_name>
전체 종료
tmux kill-server
새 창 열기 Ctrl-b c
창 닫기 Ctrl-b &
창 이동 다음 창으로 이동: Ctrl-b n
이전 창으로 이동: Ctrl-b p
패널 분할 세로 분할: Ctrl-b %
가로 분할: Ctrl-b "
패널 이동 Ctrl-b o
패널 닫기 Ctrl-b x

 


스크립팅

 

고급 I/O

 

echo 대신 printf 사용하기

  • 출력할 때 동일한 형식으로 출력하기 좋음 - 스크립트에서의 삐뚤삐뚤한 출력을 방지할 수 있음!
echo "		Birth					Name"
ls -lrt | grep -v total | while read i 
do
	n=`echo $i | awk '{print $9}'`
	birth=`stat $n | grep Birth`
	printf "%-20s %20s\n" "$birth" "$n"
done
echo ""

 

ShellCheck

 

스크립트를 올바르게 사용하고 있는지 동일한 형식으로 스크립트를 짜고 있는지 체크하는 데 사용하면 좋을 것 같다

- 스크립트라는 게 프로그래밍과 같이 다양한 방식으로 구현할 수 있기 때문에 컨벤션을 사용하자..

  1. #!(해시뱅)을 선언하여 어떤 쉘 인터프리터를 사용할지를 선언해야 한다 (이식성)
  2. read -r 없이 사용하면 \ 처리 시 문제가 발생할 수 있음
  3. ls | grep 문을 사용하면 filename이 아닌 얘들도 읽을 수 있으니 다른 방법을 사용해라
  4. 백틱 말고 $() style을 사용해라
  5. 변수는 Double quote로 word split 등을 방지해라 "$i" (split으로 인해 잘못된 명령어가 실행될 수 있음)

수정 후

#!/bin/bash
echo "		Birth					Name"

find . -maxdepth 1 -not -name '.' -type f | while read -r i 
do
	n=$(echo "$i" | awk '{print $9}')
	birth=$(stat "$n" | grep Birth)
	printf "%-20s %20s\n" "$birth" "$n"
done
echo ""

 

Shellcheck도 자주 사용할 것 같다! 

반응형