Alias shellscripting

Contents

  • Introduction
  • The Console, Terminal, and Shell
  • Source vs . (period)
  • Exporting
  • Aliasing

Introduction

맥북으로 개발환경을 처음 구축하다 보면 oh-my-zsh 을 깔며 처음 ~/.zshrc 파일을 접하게 된다. 웹에 널리고 널린 oh my zsh 꾸미기를 완료하면 대부분의 사람들은 만족하지만, 개발을 하다보면 터미널과 콘솔의 강력함을 조금씩 느끼기 시작한다 (나도그랬다). 터미널로 실행 할 수 있는 명령이나 작업은 사용자가 어떻게 사용하는지에 따라 무한하지만, cli 환경에서 linux-like 커맨드들과 shellscripting 을 3시간짜리 유튜브 강좌를 보면서 배우기보다 직접 부딪혀 보며 배우는게 더 효과적이다. 이번 포스팅에 내가 직접 부딪혀보며 배워나간 shell 의 기본을 정리해보았다.

The Console, Terminal, and Shell

이 3가지의 뜻의 경계선은 굉장히 흐리다. 하지만 이 3가지의 차이점을 확실히 인지해야만 컴퓨터의 보이지 않는 backend 에서 어떤 작업이 실행되고 있고, 어떻게 바꿀 수 있는지 알 수 있다.

Console

어떤 기기에서의 콘솔을 의미하는지 가끔마다 의미가 상이하긴 하지만, 대부분 콘솔이라고 하면 기기의 kernel 과 메인으로 연결되어 있는 primary terminal 을 의미한다. 기계의 메인 processing kernel 과 가장 밀접하게 붙어있는 input/output prompter 이라고 이해하면 쉽다.

Terminal

먼저 터미널의 정식 명칭은 Virtual Terminal 이다. 맥북에 기본적으로 깔려있는 터미널이나 iTerms 도 virtual terminal 에 해당된다. Virtual 이란 단어에서도 알 수 있듯이, 해당 터미널은 실제로 컴퓨터와 소통을 하고 있는게 아니라 실제 작업이 일어나고 있는 Console 과 소통하는 수단을 제공하는 것이다. 그렇기 때문에 맥북에서 터미널을 실행시키면 ~on ttys00x 라고 표시가 된다. 몇번째 가상 터미널이 콘솔과 소통하고 있는지 표시하는 것이다.

ttys 는 TeleTYpewriterS 의 약자다. 예전엔 타자기의 종류인 Teletypewriter 로 명령어를 실행했는데, 모든것이 디지털로 바뀌면서도 이름이 그대로 남은 케이스다.

Shell

쉘은 컴퓨터의 사용자가 로그인을 하면서 처음 실행되는 interface 이며, 주 목적은 다른 프로그램을 실행 시키는 것이다. 맥북은 OS Catalina 로 넘어오며 기존의 bash shell 을 버리고 zsh shell 을 장착했다. 보통 shellscripting 이나 shell programming 이란 워딩은 bash/zsh shell 언어로 터미널을 통해서 콘솔에 사용자화 명령을 내리는 것을 의미한다.

JS 에서 console.log 하는 것은 결국 shell 언어로 terminal 에게 명령을 내려서 콘솔에 이것을 출력하라는 것이다.

Source vs . (period)

.sh 프로그램을 터미널 cli 에서 실행 시킬 때 source 를 사용하거나 . 를 사용하는 예제를 많이 봐왔다. 하지만 둘의 차이점에 대해 정확히 서술한 글이 마땅히 없어서 테스트를 해봤다.

touch tester.sh
nano tester.sh

#!/bin/zsh
echo "Shellscript executed"
#writeout

먼저 홈디렉토리 (~) 에 실행하면 test 라는 문장을 리턴해주는 test.sh 이란 쉘스크립트를 만들었다. 홈디렉토리에서 해당 스크립트를 source 와 . 로 실행했을때의 차이는 다음과 같다.

source tester.sh
Shellscript executed
❯ source ~/tester.sh
Shellscript executed
❯ source ./tester.sh
Shellscript executed
❯ . tester.sh
.: no such file or directory: tester.sh
❯ . ~/tester.sh
Shellscript executed
❯ . ./tester.sh
Shellscript executed

확인 해 보면 한가지 경우에만 출력이 다르고 동일한 결과를 출력하는 것을 볼 수 있다. source tester.sh 과 . tester.sh 을 했을때 source 로만 실행이 되는데, 이는 source 명령어가 만약 경로가 명시되어 있지 않으면 자동으로 해당 디렉토리에서 argument 를 자동으로 찾아 실행시키기 때문이다.

위 테스트를 보며 ~/, ./ 의 차이는 순서대로 home directory 안에서, current directory 안에서 해당 파일을 찾으라는 뜻이다.

Parent/Child shell

Shell은 객체지향의 상속성을 띄기도 한다. 터미널을 처음 실행하면 해당 쉘은 부모 쉘이고, 해당 쉘에서 쉘명령어를 입력하면 부모 쉘의 모든 기본 속성이 상속된 자식 쉘이 실행된다.

❯ which python #해당 쉘의 파이썬 경로 출력
/Users/jonghyunlee/miniforge3/bin/python
❯ startconda #사용자화 miniconda 실행 명령어
❯ which python
/Users/jonghyunlee/miniconda3/bin/python
❯ zsh #자식 쉘 시작
❯ which python
/Users/jonghyunlee/miniforge3/bin/python

예시를 들어보자. 본인의 기본 쉘을 miniforge python 을 실행시키도록 설정하였기 때문에 which python 명령어를 치면 miniforge directory 에 있는 파이썬이 기본 파이썬인 것을 확인 할 수 있다. 추가적으로 설정해둔 startconda 명령어를 치면 기본 파이썬이 x_86 based 파이썬인 miniconda 파이썬으로 바뀐다. which python 명령어로 확인이 가능하다.

그이후 zsh 명령어로 부모 쉘 안에 자식 쉘을 새로 시작하라고 설정하였다. 부모 쉘은 miniforge python 을 실행하는 것이 기본 설정이기 때문에, 부모 쉘을 miniconda 로 바꿔도 자식 쉘이 부모 쉘의 기본 설정인 miniforge 를 상속받은 것을 확인할 수 있다.

해당 쉘이 부모쉘인지 자식쉘인지 확인하는 방법은 간단하다. ps -p $$ 명령어를 사용하면 된다.

❯ ps -p $$
  PID TTY           TIME CMD
72540 ttys001    0:02.98 -zsh
❯ zsh
❯ ps -p $$
  PID TTY           TIME CMD
73725 ttys001    0:00.19 zsh
❯ exit
❯ ps -p $$
  PID TTY           TIME CMD
72540 ttys001    0:03.08 -zsh

먼저 첫 명령어 라인을 보면 ps -p $$ 를 실행시키자 CMD 가 -zsh 로 출력된다. -zsh 가 부모 쉘을 의미한다. 자식 쉘을 실행시키는 zsh 명령어를 친 뒤 다시 명령어를 실행시키면 CMD가 zsh로 출력된다. zsh 앞에 - 가 없으면 자식 쉘을 의미한다. 해당 쉘을 종료하는 명령어 exit 을 사용하면 다시 부모 쉘로 돌아간다.

Exporting

자식 쉘에도 상속이 되게 부모 쉘에 새로운 변수를 설정하는 방법은 export 명령어를 통해서이다. 예시를 들어보자.

tester=123 #새로운 변수 할당echo $tester #변수 출력
123
❯ zsh #자식 쉘 시작echo $tester

tester 란 변수에 123을 할당하고, echo 로 출력하면 할당이 잘 된걸 볼 수 있다. 하지만 zsh 명령어로 자식 쉘을 실행시키면 부모 쉘에서 할당한 tester 변수가 아무것도 출력하지 않는다. 이 때 export 명령어를 사용하면 된다.

export tester=123
❯ echo $tester
123
❯ zsh
❯ echo $tester
123

새로운 자식 쉘을 실행시켜도 tester 라는 변수가 상속된 것을 볼 수 있다.

하지만 새로운 세션을 시작해서 tester 변수를 확인해보니 아무것도 출력이 되지 않았다. export 명령어는 해당 세션 내부의 자식 쉘에게 상속 을 의미하지, 새로운 세션에 상속을 하지 않는다. 그렇다면 사용자화 명령어를 사용하기 위해 새로운 세션을 열때마다 사용자화 명령을 선언하고 상속까지 해줘야 하는 것일까? 그렇지 않다. 부모 쉘의 기본 설정 자체에 변수나 함수를 할당하면 되기 때문이다.

Aliasing

부모 쉘, 즉 기본 쉘의 설정은 보통 홈디렉토리에 있는 .zshrc 파일에 선언되어 있다.

파일명 앞에 .이 있으면 해당 파일은 숨겨진 파일이란 뜻이다. 존재는 하지만 파인더 GUI 에서 확인 할 수 없다. GUI 환경에서 보고싶으면 ⌘ Command⇧ Shift . 로 toggle 할 수 있다.

VsCode 를 사용하고 있으면, 터미널에 code ~/.zshrc 명령어를 통해 VsCode 를 열어 zshrc 파일을 확인하고 수정 할 수 있다. 만약 새로운 세션에서 사용자화 명령어를 사용하고 싶으면 해당 파일을 수정하면 된다. 본인이 사용하는 예시는 다음과 같다.

# My Aliases
if [ -e $HOME/.zsh_aliases ]; then
    source $HOME/.zsh_aliases
fi

zshrc 파일에 위 조건문을 추가했다. 위치는 상관없지만, 본인은 conda init script 위에 추가했다. 해당 조건문은 만약 홈디렉토리에 zsh_aliases 라는 숨겨진 파일이 존재한다면, 해당 파일을 source 하라는 명령어다. source 하는 파일에 함수나 변수가 선언되어 있다면 자동으로 기본 쉘에 해당 함수/변수를 자동으로 선언해준다.

touch .zsh_aliases #Home directory 에 zsh_aliases 이란 숨겨진 파일 생성
code ~/.zsh_aliases #zsh_aliases 열기

zsh_aliases 라는 숨겨진 파일을 생성했다. 해당 파일에 alias 명령어로 변수를 선언하면 새로운 세션에도 해당 변수의 사용이 가능해진다.

alias testme="source ~/tester.sh"
alias bc="bc -l"
alias startconda="source ~/utils/start_miniconda.sh"
alias startforge="source ~/utils/start_miniforge.sh"

본인의 zsh_aliases 파일에 있는 alias 다. testme 에 tester.sh 을 source 하라는 명령어를 할당했기 때문에 새로운 세션에서 testme 라는 명령어를 치면 자동으로 tester.sh 가 실행된다.

Last login: Wed Feb  2 23:10:50 on ttys000
❯ testme
Shellscript executed

기본 쉘에 선언되어 있는 alias 들이 궁금하면 alias 명령어로 확인 할 수 있다. 평소에 사용하는 명령어들이 사실 alias 가 많다는 것도 확인 할 수 있다.

l='ls -lah'
la='ls -lAh'
ll='ls -lh'
ls='ls -G'

ls 도 alias 다.

alias 는 터미널 사용자화의 첫 단계이다. 평소에 자주 쓰는 긴 명령문들을 alias 화 해서 선언하면 편하게 쓸 수 있고, 나아가 단 하나의 명령어로 무거운 딥러닝 자동화 프레임워크도 컴퓨터를 킨지 3초만에 실행할 수 있다.