alias 에서 함수로, 함수에서 스크립트로

요약. 터미널에서 같은 명령을 두 번 치면 alias 를 만듭니다. 그런데 쓰다 보면 alias 로는 안 되는 일이 두 가지 나옵니다. if 문을 넣을 수 없고, 스크립트 안에서는 아예 동작하지 않습니다. 명령에 이름을 붙이는 방법은 alias 말고도 두 가지가 더 있습니다. 함수와 스크립트 파일입니다. 셋 중 어느 것을 쓸지 정하는 기준을, alias 가 무엇인지부터 짚어가며 정리했습니다.

도토리 한글 키보드 - 폰을 PC·TV 의 블루투스 키보드로

제가 만든 무료 앱입니다. 많이 써 주세요.

alias 는 명령의 첫 단어를 바꿔줍니다

alias 는 명령의 첫 단어를 미리 정해둔 다른 문자열로 바꿔주는 기능입니다. 셸이 명령줄을 읽을 때 글자를 갈아끼우고, 그 뒤는 원래 명령이 그대로 실행됩니다. 만드는 것도 한 줄이고 지우는 것도 unalias 한 줄입니다. 단순하지만 세 가지 일을 합니다.

첫째, 타수를 줄입니다. 하루에 스무 번 치는 명령이 두 글자가 됩니다.

alias gs='git status'
alias la='ls -a'

둘째, 옵션을 외우지 않아도 됩니다. 타수 줄이는 것보다 이게 더 쓸모 있습니다. -w 는 공백만 바뀐 줄을 무시하는 옵션인데, 필요할 때마다 기억해 내는 것보다 이름 안에 넣어두는 편이 확실합니다.

alias gdu='git --no-pager diff -w'
alias rgrep='grep -rni'

셋째, 도구의 기본 동작을 바꿉니다. 같은 이름으로 다시 정의하는 방법입니다.

alias lsd='lsd --group-dirs=first'

자기가 자기를 부르니 무한히 반복될 것 같지만 그렇게 되지 않습니다. 글자를 갈아끼우는 일이 첫 단어에 한 번만 일어나기 때문입니다. 그래서 lsd 는 늘 폴더를 먼저 보여주는 명령이 됩니다.

$ lsd
zdir
a.txt
b.txt

원래 동작이 필요할 때는 백슬래시를 앞에 붙입니다. \lsd 는 옵션이 붙지 않은 원본입니다. 지금 무엇이 걸려 있는지 보려면 type lsd, 전체 목록은 인자 없이 alias 입니다.

if 문이 필요하거나 폴더를 옮겨야 하면 함수입니다

글자를 갈아끼우는 것이 전부이니 못 하는 일도 있습니다. if 문을 넣을 수 없고, 인자를 명령 중간에 끼울 수도 없습니다. 이럴 때 함수로 바꿉니다.

제 gd 는 diff 를 보기 좋게 꾸며주는 delta 가 깔린 PC 와 없는 PC 를 함께 써야 해서 함수입니다.

gd() {
    if command -v delta >/dev/null 2>&1; then
        git -c core.pager=delta diff -w "$@"
    else
        git --no-pager diff -w "$@"
    fi
}

두 번째는 우회할 방법이 아예 없습니다. 스크립트를 실행하면 별도 프로세스가 뜨는데, 그 프로세스는 자기를 부른 셸의 현재 폴더를 바꿀 수 없습니다. 스크립트 안에서 cd 한 결과는 그 프로세스와 함께 사라집니다.

실행 전: /tmp/cdtest
/tmp/cdtest/sub     <- 스크립트가 cd 한 뒤 찍은 pwd
실행 후: /tmp/cdtest <- 부모 셸은 그대로

그래서 파일 관리자 yazi 로 폴더를 옮겨 다닌 뒤 그 자리에 셸을 남기려면 함수여야 합니다. yazi 가 끝난 위치를 임시 파일로 받아, 그 경로로 셸에서 직접 cd 합니다.

yz() {
    local tmp="$(mktemp -t yazi-cwd.XXXXXX)"
    yazi "$@" --cwd-file="$tmp"
    local cwd
    if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
        cd -- "$cwd"
    fi
    rm -f -- "$tmp"
}

같은 코드를 스크립트 파일로 만들면 cd 가 그 프로세스 안에서만 일어나 아무 효과가 없습니다.

사람이 아니라 프로그램이 부를 것이면 파일로 만듭니다

마지막은 조금 다른 이야기입니다. alias 는 사람이 직접 명령을 치는 셸에서만 동작합니다. 이런 셸을 대화형 셸이라고 부릅니다. 두 줄짜리 스크립트로 확인했습니다.

$ cat t.sh
alias hello='echo 안녕'
hello

$ bash t.sh
t.sh: line 2: hello: command not found

bash 매뉴얼에 그렇게 적혀 있습니다. "Aliases are not expanded when the shell is not interactive." 예외는 expand_aliases 옵션뿐입니다. 스크립트 첫 줄에 shopt -s expand_aliases 를 넣으면 같은 코드가 정상 동작합니다.

그래서 Makefile 안의 명령, CI 작업, AI 코딩 에이전트가 부르는 명령은 alias 로 둘 수 없습니다. 사람이 치는 것이 아니라 프로그램이 부르는 것이라 그렇습니다. 이럴 때 파일로 만듭니다. 할 일은 세 줄입니다.

mkdir -p ~/bin                      # 스크립트를 모아 둘 폴더
chmod +x ~/bin/git-log-file.sh      # 실행 권한
echo 'export PATH="$PATH:$HOME/bin"' >> ~/.bashrc

그 뒤로는 어느 폴더에 있든 git-log-file.sh 라는 이름만으로 부릅니다. 직접 칠 때나 Makefile 에서나 에이전트가 부를 때나 같은 명령입니다.

worktree 여러 개를 한 줄로 병합하는 글에서 다룬 병합 스크립트가 이렇게 파일로 둔 실물입니다. 제가 손으로도 치고 에이전트도 부르므로 파일이어야 했습니다.

셋 중 하나만 골라야 하는 것은 아닙니다. 파일로 만든 뒤 그것을 다시 alias 로 가리켜두면 치는 글자가 줄어듭니다.

alias glf='~/bin/git-log-file.sh'

정리

방법이럴 때 씁니다사는 곳
alias첫 단어만 바꾸면 되는 일직접 치는 셸
함수if 문이 필요하거나 폴더를 옮겨야 하는 일직접 치는 셸
스크립트 파일스크립트·Makefile·CI·에이전트가 부르는 일PATH 에 얹은 파일

alias 는 첫 단어를 바꿔주는 것이 전부입니다. 그래서 만들기 쉽고, 못 하는 일도 분명합니다. if 문이나 폴더 이동이 필요하면 함수로 바꾸고, 사람이 아니라 프로그램이 부를 것이면 파일로 만듭니다.

지금 바로 할 수 있는 것은 인자 없이 alias 를 쳐서 목록을 보는 것입니다. 그 중에 if 문을 넣고 싶었던 것과 스크립트에서 부르고 싶었던 것이 있다면, 그것부터 함수나 파일로 옮기면 됩니다.