새 리눅스 환경을 받을 때마다 반복하는 쉘 설정을 모았다. /bin/sh가 기대와 다르게 동작해서 당황하는 지점, 기본 쉘을 바꿨는데 안 바뀐 것처럼 보이는 지점, zsh로 넘어갈 때 챙길 것, 그리고 ls 색상 설정까지 매번 다시 찾아보던 것들을 한 곳에 정리한다.
/bin/sh는 bash가 아니다
우분투에서 /bin/sh는 bash가 아니라 dash를 가리킨다.
ls -al /bin/sh
# /bin/sh -> dashUbuntu 위키의 DashAsBinSh 문서는 그 이유로 두 가지를 든다. 하나는 속도다: “bash는 대화형 사용에 적합한 훌륭한 쉘이지만, dash에 비해 크고 시작·동작이 느리다.” 다른 하나는 POSIX 준수다: Debian 정책상 /bin/sh를 인터프리터로 지정한 스크립트는 POSIX 기능만 써야 한다.
문제는 #!/bin/sh 셔뱅을 달아 놓고 bash 문법을 쓰는 스크립트다. 실행은 되지만 dash가 그 문법을 이해하지 못해 조용히 다르게 동작한다. 대표적인 예가 [ 안의 == 비교다. bash에서는 되지만 POSIX test는 =만 인정한다.
echo 'if [ "a" == "a" ]; then echo ok; fi' > /tmp/t.sh
bash /tmp/t.sh # ok
dash /tmp/t.sh # /tmp/t.sh: 1: [: a: unexpected operatordash는 에러만 찍고 스크립트를 죽이지 않는다. if 조건이 그냥 거짓으로 처리되고 스크립트는 계속 실행되니, 원인을 찾기가 더 까다롭다. 같은 문서가 드는 다른 예로 source 대신 .을 써야 하는 것, 배열 변수를 쓸 수 없는 것도 있다.
결론: /bin/sh를 바꾸지 말고 셔뱅을 고친다. 정말 bash 문법이 필요한 스크립트라면 셔뱅을 #!/bin/bash로 명시하면 된다.
dpkg-reconfigure dash와 chsh는 다른 것
둘은 서로 다른 쉘을 바꾼다.
sudo dpkg-reconfigure dash # /bin/sh를 바꾼다 (dash <-> bash)
chsh -s $(which bash) # 로그인 쉘을 바꾼다터미널을 열었을 때 뜨는 “내 기본 쉘”을 바꾸고 싶다면 대부분 원하는 건 후자, chsh다. dpkg-reconfigure dash는 스크립트 실행에 쓰이는 /bin/sh만 바꿀 뿐, 로그인 쉘에는 영향이 없다.
chsh로 바꾼 로그인 쉘은 바로 적용되지 않는다. passwd(5)에 따르면 로그인 쉘 필드는 “로그인할 때 실행할 프로그램”이고, chsh(1)은 이 필드를 고치는 명령일 뿐이다. 즉 이미 열려 있는 터미널 세션에는 반영되지 않고, 다음 로그인부터 적용된다. 바꾼 직후 새 터미널을 열어도 그대로면 당황하지 말고 로그아웃 후 재로그인(또는 재부팅)하면 된다.
zsh와 oh-my-zsh
sudo apt install zsh
chsh -s $(which zsh)역시 로그인 쉘이므로 재로그인이 필요하다.
oh-my-zsh는 공식 설치 스크립트로 넣는다.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"oh-my-zsh 저장소 문서에 따르면 이 스크립트는 기존 ~/.zshrc를 지우지 않고 ~/.zshrc.pre-oh-my-zsh로 이름을 바꿔 남긴 뒤 그 자리에 새 ~/.zshrc를 놓는다. 커스텀 설정이 있는 상태에서 curl | sh를 돌리기 전에 알아 둘 사실이다. 필요한 설정은 설치 후 백업 파일에서 새 .zshrc로 옮기면 된다.
자주 쓰는 alias 하나:
alias ll="ls -alhtr"어느 파일에 넣나 — 로그인 셸과 대화형 셸
“프로파일에 넣는다”고 할 때 그 파일이 하나가 아니다. bash는 어떻게 시작됐는지에 따라 다른 파일을 읽는다.
| 셸이 시작된 형태 | 읽는 파일 |
|---|---|
로그인 셸 (콘솔 로그인, ssh 호스트, bash --login) | /etc/profile → ~/.bash_profile·~/.bash_login·~/.profile 중 먼저 찾은 하나만 |
로그인 아닌 대화형 셸 (터미널에서 bash, 새 탭) | /etc/bash.bashrc → ~/.bashrc |
비대화형 (ssh 호스트 'cmd', 스크립트) | 아무것도 안 읽는다 |
임시 홈에 마커를 심어 실제로 확인한 결과다.
$ env HOME=$T bash --login -i -c true
[.bash_profile 읽힘]
$ rm $T/.bash_profile && env HOME=$T bash --login -i -c true
[.bash_login 읽힘]
$ rm $T/.bash_login && env HOME=$T bash --login -i -c true
[.profile 읽힘]
$ env HOME=$T bash -i -c true
[.bashrc 읽힘]
$ env HOME=$T bash -c "echo 끝"
끝 ← 시작 파일을 하나도 안 읽었다세 파일 중 하나만 읽힌다는 게 핵심이다. .bash_profile을 만드는 순간 .profile은 통째로 무시된다. 우분투에서 잘 쓰던 .profile 설정이 어느 날 안 먹는다면 대개 이것 때문이다.
우분투 기본값이 이 헷갈림을 키운다. /etc/skel에는 .bash_profile이 아예 없고 .profile·.bashrc·.bash_logout 셋뿐인데, 그 .profile이 .bashrc를 불러 준다.
# /etc/skel/.profile
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi그래서 어디에 써도 다 먹는 것처럼 보인다. RHEL/CentOS 계열은 .bash_profile이 같은 일을 한다. 그 연결은 배포판이 만들어 준 관행이지 셸의 규칙이 아니다.
넣을 자리를 고르는 기준은 이렇다.
PATH·환경변수처럼 한 번 정하면 자식 프로세스로 상속되는 것 →.bash_profile(없으면.profile)- alias·프롬프트·셸 옵션처럼 대화형 셸마다 새로 필요한 것 →
.bashrc. alias는 상속되지 않으므로 여기가 아니면 새 탭에서 사라진다. ssh 호스트 'command'로 원격 명령을 한 줄 실행하면 둘 다 안 읽는다. 로컬에선 되는 명령이 원격에서 “command not found”가 나는 흔한 이유다 — 절대경로를 쓰거나ssh 호스트 'bash -lc "command"'로 로그인 셸을 태운다.
zsh는 파일 이름이 다르고 순서도 하나 더 있다: .zshenv(항상) → .zprofile(로그인) → .zshrc(대화형) → .zlogin(로그인, .zshrc 뒤).
새로 만드는 계정에 기본으로 깔리게 하려면 /etc/skel/에 파일을 두면 된다. useradd가 홈 디렉터리를 만들 때 통째로 복사한다. 이미 있는 계정에는 소급 적용되지 않는다.
프롬프트(PS1)
프롬프트 모양은 PS1이 정한다. 백슬래시 이스케이프를 쓰며, man bash의 PROMPTING 항목이 전체 목록이다. 자주 쓰는 것만 실제 확장 결과와 함께 옮긴다.
| 이스케이프 | 뜻 | 확장 예 |
|---|---|---|
\u | 사용자 이름 | ewanshin |
\h | 호스트명(첫 . 앞까지) | metrolegion |
\H | 호스트명 전체 | metrolegion |
\w | 현재 경로(홈은 ~로 축약) | /mnt/d/project/quartz |
\W | 현재 경로의 마지막 조각만 | quartz |
\$ | root면 #, 아니면 $ | $ |
\t | 24시간 HH:MM:SS | 17:28:39 |
\A | 24시간 HH:MM | 17:28 |
\! | 히스토리 번호 | 1 |
\n | 줄바꿈 — 경로가 길면 두 줄로 |
바꾸기 전에 결과를 보고 싶으면 셸을 더럽히지 말고 파라미터 확장 ${PS1@P} 로 찍어 본다(bash 4.4+). 위 표도 이걸로 뽑았다.
PS1='\u@\h:\w\$ '
echo "${PS1@P}" # ewanshin@metrolegion:/mnt/d/project/quartz$색을 넣을 때 \[ \]를 빠뜨리지 않는다
색은 ANSI 이스케이프(\e[36;1m 같은 것)로 넣고, 그 부분을 반드시 \[와 \]로 감싼다.
export PS1="\[\e[36;1m\]\u@\[\e[32;1m\]\h:\[\e[31;1m\]\w:> \[\e[0m\]"확장하면 이렇게 된다(제어문자를 cat -v로 드러낸 것).
$ printf "%s\n" "${PS1@P}" | cat -v
^[[36;1mewanshin@^[[32;1mmetrolegion:^[[31;1m/mnt/d/project/quartz:> ^[[0mman bash는 \[를 “begin a sequence of non-printing characters”로 정의한다. bash가 프롬프트의 화면상 길이를 셀 때 이 구간을 제외하기 위한 표시다. 감싸지 않으면 색 코드까지 글자로 세어 커서 위치를 잘못 계산하고, 긴 명령을 편집하거나 위 화살표로 히스토리를 넘길 때 줄이 깨져 보인다. 색이 나오니 맞게 쓴 줄 알기 쉬운데, 증상은 한참 뒤에 나온다.
마지막의 \[\e[0m\]는 색을 되돌리는 것이다. 이게 없으면 명령어와 출력까지 프롬프트 색으로 물든다.
PS2는 명령이 안 끝났을 때 나오는 두 번째 프롬프트다(기본값 > ). zsh는 PROMPT를 쓰고 이스케이프 문법도 달라서, 같은 프롬프트가 %n@%m:%~%# 가 된다.
오래된 예제에서 걸러야 할 것
프롬프트 설정을 검색하면 .bash_profile 예제가 함께 나오는데, 지금 기준으로 손봐야 하는 줄들이 섞여 있다.
-
export TERM=linux— 터미널 종류는 접속한 터미널이 정해 주는 값이라 사람이 강제할 게 아니다. 강제하면 오히려 색이 줄어든다.$ TERM=linux tput colors 8 $ TERM=xterm-256color tput colors 256 -
alias vi='vim $*'— alias는 인자를 받지 않는다. 텍스트 치환이라 인자는 어차피 뒤에 붙고,$*는 빈 값으로 확장돼 아무 일도 하지 않는다.$ alias t='echo [$*]' $ t hello world [] hello world ← $*는 비어 있고 인자는 그냥 뒤에 붙었다alias vi=vim이면 충분하다. 인자를 실제로 다뤄야 하면 alias가 아니라 함수를 쓴다. -
alias mvn='/usr/local/apache-maven-3.0.4/bin/mvn'처럼 버전이 박힌 절대경로 alias — 업그레이드할 때마다 고쳐야 한다.PATH에 심링크 디렉터리를 넣고 그쪽을 갱신하는 편이 낫다.
ls 색상
터미널에서 ls 출력에 색상을 입히는 설정이다. 여기서 제일 먼저 알아야 할 것은 ls가 두 종류라는 사실이다. macOS의 기본 ls는 BSD 계열이고 리눅스의 기본 ls는 GNU coreutils인데, 둘은 색상 설정 방식이 완전히 다르고 서로의 환경변수를 무시한다. 한쪽 설정을 다른 쪽에 복사해 넣으면 아무 일도 일어나지 않는다.
macOS (BSD ls) | 리눅스 (GNU ls) | |
|---|---|---|
| 색상 켜기 | CLICOLOR=1 또는 ls -G | ls --color=auto |
| 색 규칙 변수 | LSCOLORS | LS_COLORS |
| 규칙 형식 | 22글자 위치 기반 문자열 | 키=코드 목록(콜론 구분) |
| 생성 도구 | 없음(직접 씀) | dircolors |
설정은 셸 프로파일(.bash_profile, .zshrc 등)에 넣는다.
폴더 색만 바꾸고 싶다면
가장 흔한 요구가 이것이라 먼저 적는다. 양쪽 한 줄씩이다.
# macOS — LSCOLORS의 '첫 두 글자'가 디렉터리다 (글자색, 배경색)
export CLICOLOR=1
export LSCOLORS=Exfxcxdxbxegedabagacad # Ex = 굵은 파랑 글자 + 기본 배경
# 리눅스 — di 키가 디렉터리다
export LS_COLORS="$LS_COLORS:di=01;33" # 굵은 노랑리눅스 쪽에서 기존 LS_COLORS 뒤에 그냥 이어 붙이면 되는 이유는 같은 키가 여러 번 나올 때 마지막 정의가 이기기 때문이다. 앞·중간·뒤에 di를 서로 다른 값으로 세 번 넣고 확인해 보면 항상 마지막 값으로 표시된다. 덕분에 기본값 전체를 다시 쓰지 않고 원하는 키만 덧칠할 수 있다.
CLICOLOR=1
ls가 색상을 자동으로 출력하도록 켜는 스위치다. (0 또는 미설정이면 색상 없음)
LSCOLORS의 구조
LSCOLORS는 22글자 = 11쌍으로 이루어진다. 각 쌍은 [글자색][배경색] 순서이고, 11개의 쌍은 정해진 파일 종류 순서를 나타낸다.
Eh fx cx dx bx eg ed ab ag ac ad
│ │ │ │ │ │ │ │ │ │ └ 기타 쓰기 가능 디렉토리(스티키 비트 없음)
│ │ │ │ │ │ │ │ │ └─── 기타 쓰기 가능 디렉토리(스티키 비트)
│ │ │ │ │ │ │ │ └────── setgid 실행 파일
│ │ │ │ │ │ │ └───────── setuid 실행 파일
│ │ │ │ │ │ └──────────── 문자 장치(character special)
│ │ │ │ │ └─────────────── 블록 장치(block special)
│ │ │ │ └────────────────── 실행 파일(executable)
│ │ │ └───────────────────── 파이프(pipe/FIFO)
│ │ └──────────────────────── 소켓(socket)
│ └─────────────────────────── 심볼릭 링크(symbolic link)
└────────────────────────────── 디렉토리(directory)
색상 코드 (한 글자)
| 글자 | 색 | 글자 | 색 |
|---|---|---|---|
a | 검정(black) | b | 빨강(red) |
c | 초록(green) | d | 갈색/노랑(brown) |
e | 파랑(blue) | f | 자홍(magenta) |
g | 청록(cyan) | h | 밝은 회색(light grey) |
x | 기본색(default) | X | 기본색 + 굵게/밑줄 |
- 대문자(
A~H) = 해당 색의 굵게/밝게(bold) 버전. 예:E= 굵은 파랑. - 배경색 자리에
x를 쓰면 터미널 기본 배경을 사용한다.
이 설정값 해석 — Ehfxcxdxbxegedabagacad
| 쌍 | 대상 | 글자색 | 배경색 |
|---|---|---|---|
Eh | 디렉토리 | 굵은 파랑(E) | 밝은 회색(h) |
fx | 심볼릭 링크 | 자홍(f) | 기본 |
cx | 소켓 | 초록(c) | 기본 |
dx | 파이프 | 갈색(d) | 기본 |
bx | 실행 파일 | 빨강(b) | 기본 |
eg | 블록 장치 | 파랑(e) | 청록(g) |
ed | 문자 장치 | 파랑(e) | 갈색(d) |
ab | setuid 실행 | 검정(a) | 빨강(b) |
ag | setgid 실행 | 검정(a) | 청록(g) |
ac | 스티키 쓰기 디렉토리 | 검정(a) | 초록(c) |
ad | 쓰기 디렉토리(스티키 없음) | 검정(a) | 갈색(d) |
기본값은
exfxcxdxbxegedabagacad이며, 이 설정은 첫 쌍만ex(파랑 글자·기본 배경) →Eh(굵은 파랑 글자·밝은 회색 배경)로 바꿔 디렉토리를 더 눈에 띄게 한 것이다.
GNU/Linux — LS_COLORS와 dircolors
리눅스는 --color=auto로 색을 켜고, 규칙은 LS_COLORS에 담는다. 우분투라면 기본 ~/.bashrc가 이미 다 해 준다.
# 우분투 22.04 기본 ~/.bashrc
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
...
fi여기서 읽어야 할 것은 alias가 아니라 ~/.dircolors가 있으면 그걸 우선 읽는다는 조건이다. 즉 우분투에서는 .bashrc를 건드릴 필요 없이 ~/.dircolors 파일만 두면 된다.
LS_COLORS는 키=코드를 콜론으로 이은 문자열이고, 코드는 ANSI SGR 숫자를 세미콜론으로 이어 쓴다(01 굵게, 04 밑줄, 30–37 글자색, 40–47 배경색, 38;5;N 256색). di=01;34는 “디렉터리 = 굵게 + 파란 글자”다.
기본값은 dircolors로 확인한다. -p는 사람이 읽는 형식, -b는 셸에 넣을 export 형식이다.
dircolors -p | less # 기본 규칙 전체
dircolors -b # export LS_COLORS='rs=0:di=01;34:ln=01;36:...'파일 종류 키의 기본값(coreutils 8.32 기준):
| 키 | 대상 | 기본값 |
|---|---|---|
di | 디렉터리 | 01;34 |
ln | 심볼릭 링크 | 01;36 |
or | 끊어진 심볼릭 링크 | 40;31;01 |
ex | 실행 파일 | 01;32 |
pi | 파이프 | 40;33 |
so | 소켓 | 01;35 |
bd | 블록 장치 | 40;33;01 |
cd | 문자 장치 | 40;33;01 |
su | setuid 실행 파일 | 37;41 |
sg | setgid 실행 파일 | 30;43 |
ca | capability 붙은 파일 | 30;41 |
st | 스티키 디렉터리(타인 쓰기 불가) | 37;44 |
tw | 스티키 + 타인 쓰기 가능 디렉터리 | 30;42 |
ow | 타인 쓰기 가능 디렉터리(스티키 없음) | 34;42 |
확장자별 규칙(*.tar=01;31 같은 것)도 같은 문자열에 들어간다.
바꾸는 방법은 두 가지고, 고르는 기준은 “몇 개를 바꾸느냐”다.
# 1) 키 몇 개만 바꿀 때 — 기존 값 뒤에 덧붙인다 (마지막 정의가 이긴다)
export LS_COLORS="$LS_COLORS:di=01;33:ow=01;34"
# 2) 많이 바꿀 때 — 파일로 관리한다
dircolors -p > ~/.dircolors # 반드시 전체 기본값을 받아서 시작한다
vi ~/.dircolors # DIR 01;33 같은 줄을 고친다
~/.dircolors에 필요한 줄만 쓰면 나머지 색이 전부 사라진다
dircolors -b는 파일에 적힌 것만 내보낸다.DIR 01;33한 줄만 넣고 확인하면LS_COLORS가di=01;33:하나로 끝난다 — 링크·실행 파일·확장자 색이 통째로 날아간 상태다. 그래서dircolors -p로 기본값 전체를 덤프한 뒤 편집한다.
초록 배경 폴더의 정체 — ow와 tw
외장 디스크나 chmod 777 한 폴더가 초록 배경으로 나와 글자가 안 보이는 그 현상이다. 터미널 테마 문제가 아니라 기본값이다.
mkdir normal ow777 tw
chmod 777 ow777 # 타인 쓰기 가능
chmod 1777 tw # 타인 쓰기 가능 + 스티키
ls --color=always -1 | cat -v^[[01;34mnormal^[[0m # di=01;34 → 굵은 파랑
^[[34;42mow777^[[0m # ow=34;42 → 파란 글자 + 초록 배경
^[[30;42mtw^[[0m # tw=30;42 → 검은 글자 + 초록 배경
/tmp가 1777이라 늘 초록인 것도 같은 이유다(tw). FAT/exFAT 파일시스템은 유닉스 퍼미션이 없어 마운트하면 전부 777로 보이므로 USB 안이 통째로 초록이 된다 — 퍼미션을 고칠 문제가 아니라 색 규칙을 고칠 문제다.
export LS_COLORS="$LS_COLORS:ow=01;34:tw=01;34" # 디렉터리와 같은 색으로 통일두 체계 대응표
LSCOLORS의 11쌍은 순서가 곧 파일 종류다. GNU 키와 나란히 놓으면 이렇게 대응한다.
LSCOLORS 위치 | 대상 | GNU 키 | GNU 기본값 |
|---|---|---|---|
| 1 | 디렉터리 | di | 01;34 |
| 2 | 심볼릭 링크 | ln | 01;36 |
| 3 | 소켓 | so | 01;35 |
| 4 | 파이프 | pi | 40;33 |
| 5 | 실행 파일 | ex | 01;32 |
| 6 | 블록 장치 | bd | 40;33;01 |
| 7 | 문자 장치 | cd | 40;33;01 |
| 8 | setuid 실행 파일 | su | 37;41 |
| 9 | setgid 실행 파일 | sg | 30;43 |
| 10 | 스티키 + 타인 쓰기 가능 | tw | 30;42 |
| 11 | 타인 쓰기 가능 | ow | 34;42 |
LSCOLORS에 없는 것도 있다. GNU 쪽 or(끊어진 링크)·ca(capability)·st(스티키만)·확장자별 규칙은 BSD ls에 대응하는 자리가 없다. 표현력은 LS_COLORS가 넓다.
두 OS에서 같은 설정을 쓰려면
LSCOLORS와 LS_COLORS를 동시에 이해하는 ls는 없다. 그래서 방법은 셋이고, 실제로 고르게 되는 건 앞의 둘이다.
1. macOS에 GNU ls를 깔고 LS_COLORS로 통일한다. 색 규칙을 담은 파일이 한 벌로 줄어드니 여러 머신을 오갈 때 이게 제일 편하다. 아래 “한 벌로 쓰는 설정”에 전체를 적었다.
brew install coreutils # gls, gdircolors 등 g 접두사로 설치된다
alias ls='gls --color=auto'
eval "$(gdircolors -b ~/.dircolors)"2. 프로파일에서 OS로 분기한다. 기본 ls를 그대로 쓰고 싶을 때다. 공유 dotfiles에서 흔한 형태다.
case "$(uname -s)" in
Darwin)
export CLICOLOR=1
export LSCOLORS=Exfxcxdxbxegedabagacad
;;
Linux)
alias ls='ls --color=auto'
eval "$(dircolors -b)"
export LS_COLORS="$LS_COLORS:ow=01;34:tw=01;34"
;;
esac3. ls 대체 도구를 쓴다. eza 문서는 EZA_COLORS의 값이 LS_COLORS의 값을 덮어쓴다고 밝히고 있다 — 기존 LS_COLORS를 다시 쓰지 않아도 된다는 뜻이다. 양쪽 OS에서 같은 바이너리를 쓰므로 색 설정도 한 벌로 끝나지만, ls 자체를 바꾸는 선택이라 접속만 하는 서버까지 통일하기는 어렵다.
한 벌로 쓰는 설정
위 1번(coreutils)으로 통일하는 쪽을 실제 설정으로 적어 둔다. 목표는 .zshrc와 ~/.dircolors를 그대로 복사해 두 OS에서 쓰는 것이다.
1) macOS에 GNU coreutils 설치
brew install coreutilsHomebrew의 coreutils 주의사항(caveats)은 이렇게 안내한다 — “macOS가 제공하는 명령들, 그리고 dir·dircolors·vdir은 접두사 g를 붙여 설치했다. 원래 이름으로 쓰고 싶으면 PATH에 gnubin 디렉터리를 추가하면 된다.” 즉 설치 직후 쓸 수 있는 이름은 gls·gdircolors다.
gls --version | head -1 # ls (GNU coreutils) 9.x접두사 없이 쓰는 방법도 있긴 하다.
export PATH="$HOMEBREW_PREFIX/opt/coreutils/libexec/gnubin:$PATH"HOMEBREW_PREFIX는 애플 실리콘에서 /opt/homebrew, 인텔 맥에서 /usr/local이다(brew shellenv가 설정해 준다).
다만 이건 ls뿐 아니라 date·sed·readlink 등 겹치는 명령 전부를 GNU 판으로 갈아치운다. macOS를 전제로 쓴 기존 스크립트가 BSD 옵션을 쓰고 있으면 그때부터 깨진다. 색상 통일이 목적이라면 PATH를 건드리지 말고 g 접두사 그대로 두고 alias로만 가리키는 편이 안전하다.
2) 셸 프로파일 — 양쪽에서 같은 스니펫
gls가 있으면 그걸, 없으면 기본 ls를 쓴다. OS를 판별하는 대신 명령의 존재로 분기하므로 uname 갈래가 필요 없고, coreutils를 아직 안 깐 맥에서도 그냥 돌아간다.
# 어느 OS에서도 같은 파일을 쓴다
if command -v gls >/dev/null 2>&1; then
LS_CMD=gls; DIRCOLORS_CMD=gdircolors # macOS + coreutils
else
LS_CMD=ls; DIRCOLORS_CMD=dircolors # 리눅스
fi
alias ls="$LS_CMD --color=auto"
test -r ~/.dircolors \
&& eval "$($DIRCOLORS_CMD -b ~/.dircolors)" \
|| eval "$($DIRCOLORS_CMD -b)"
export LS_COLORS="$LS_COLORS:ow=01;34:tw=01;34" # 초록 배경 폴더 끄기alias ls="$LS_CMD ..."를 큰따옴표로 쓴 것은 alias를 만드는 시점에 값을 박아 넣기 위해서다. 결과는 alias ls='gls --color=auto' 또는 alias ls='ls --color=auto'가 된다.
통일한 뒤에는 CLICOLOR·LSCOLORS·ls -G를 더 쓰지 않는다. GNU ls가 무시하는 설정이라 남겨 두면 나중에 “왜 안 먹지”의 원인이 된다.
3) ~/.dircolors를 dotfiles에 넣는다
색 규칙 본체는 이 파일 하나다. 리눅스 머신에서 기본값을 덤프해 편집하고, 그대로 맥에 복사한다.
dircolors -p > ~/.dircolors # 전체 기본값에서 시작 (부분만 쓰면 나머지 색이 사라진다)
vi ~/.dircolors # DIR, OTHER_WRITABLE 등을 고친다형식은 GNU coreutils 공통이라 gdircolors가 같은 파일을 읽는다. 두 머신의 coreutils 버전이 달라 한쪽에만 있는 키가 있어도, 모르는 줄은 그냥 무시되므로 파일 하나를 공유해도 된다.
4) 확인
ls --version | head -1 # ls (GNU coreutils) ... 가 떠야 통일된 것
alias ls # gls --color=auto (맥) / ls --color=auto (리눅스)
mkdir -p /tmp/t/pub && chmod 777 /tmp/t/pub && ls --color=always -1 /tmp/t | cat -v
# ^[[01;34mpub^[[0m ← 초록 배경(^[[34;42m)이 아니라 굵은 파랑이면 성공리눅스 쪽 내용과 위 분기 스니펫은 WSL2의 우분투 22.04(coreutils 8.32)에서 직접 확인했다(
gls·gdircolors자리에 껍데기 스크립트를 놓아 양쪽 분기를 모두 실행). macOS 쪽LSCOLORS·CLICOLOR동작과 Homebrew 설치 경로는 각각 BSDls문서와 Homebrew 문서를 근거로 적었다.
참고
- DashAsBinSh — Ubuntu가
/bin/sh로 dash를 쓰는 이유(속도, POSIX 준수)와 대표적인 bashism 목록을 확인했다. - ohmyzsh/ohmyzsh — 설치 스크립트가 기존
~/.zshrc를.zshrc.pre-oh-my-zsh로 백업한다는 동작을 확인했다. - bash 의 프롬프트(prompt) 설정 및 profile 설정 — 색을 넣은
PS1예제와/etc/skel/.bash_profile로 새 계정에 기본 설정을 까는 방법을 참고했다. man bash의 PROMPTING·INVOCATION 항목 — 프롬프트 이스케이프 전체 목록과\[가 “begin a sequence of non-printing characters”라는 정의, 그리고 로그인 셸이~/.bash_profile·~/.bash_login·~/.profile중 하나만 읽는다는 규칙을 확인했다.- chsh(1), passwd(5) — chsh가 바꾸는 로그인 쉘 필드가 “로그인할 때 실행할 프로그램”이라 다음 로그인부터 적용된다는 점을 확인했다.
- FreeBSD
ls(1)— BSDls가LSCOLORS의 11쌍을 어떤 순서로 읽는지, 색 지정 문자(a–h,x,X, 대문자)의 의미,-G가--color=auto와 동등하다는 설명을 확인했다. - GNU coreutils —
dircolors—-p(사람이 읽는 기본값 덤프)와-b(셸export형식) 옵션의 역할을 확인했다. - Homebrew —
coreutils포뮬라 — macOS와 겹치는 명령 및dir·dircolors·vdir이g접두사로 설치되고,libexec/gnubin을PATH에 넣으면 원래 이름으로 쓸 수 있다는 caveats를 확인했다. - eza —
eza_colors(5)—EZA_COLORS가LS_COLORS를 덮어쓰는 관계라 기존LS_COLORS를 다시 쓸 필요가 없다는 서술을 확인했다. - Mac 터미널 컬러링 초기 설정 — 검은 배경 기준 macOS 실사용 설정값(
CLICOLOR=1,LSCOLORS=GxFxCxDxBxegedabagaced,alias ls='ls -GFh')의 예를 참고했다.