LINUX
2018.10.01 / 21:44

bash shell

Chitta
추천 수 3

bash는 GNU 재단의 대표적인 작품으로 20년 이상의 역사를 가진 쉘로 대부분의 리눅스 배포판 및 Mac OS X가 기본 쉘로 채택한 쉘이다. 예전부터 유닉스에서 사용하던  Bourne shell(sh)을 대치하려고 만들었으므로 sh와 호환되면서 다양하고 편리한 기능을 포함하고 있으므로 효율적으로 작업을 할 수 있으며 타이핑을 최소화하고 실수를 방지할 수 있다.

특징

탭 완성(tab completion)

bash는 탭 완성이라는 아주 편리한 기능을 제공하고 있다. 사용하려는 명령의 일부만 입력하고 명령 완성 단축키인  탭키를 누르면 해당 명령을 완성해 준다.

만약 입력된 명령어와 중복되는 명령이 많을 경우 탭을 한 번 더 누르면 중복되는 모든 명령을 표시해 준다. 다음 화면처럼 ssh-copy-id 를 실행할 경우 ss 만 치고 탭키를 누르면 ss 로 시작되는 모든 명령어를 표시해 준다.

명령 완성 화면

이후 ssh 를 치고 또 탭을 칠 경우 ssh 로 시작하는 명령어가 많으므로 ssh 까지만 완성해주고 중복되는 명령어들을 표시해 준다. 이 상태에서 ssh-c 를 입력후 탭 키를 누르면 ssh-c 로 시작되는 명령어는 ssh-copy-id 밖에 없으므로 ssh-copy-id 명령을 완성해 준다.


탭 완성 기능은 파일명에 대해서도 쓸 수 있다. 만약 vi 로 bash 의 설정 파일인 .bash_profile 을 편집할 경우 vi .ba 만 치고 탭 키를 누를 경우 아래와 같이 vi .bash로 명령행을 완성해 준다.

이 상태에서 탭을 한 번 더 누르면 .bash 로 시작하는 파일명들을 모두 표시해 준다. 여기에서 vi .bash_p 까지만 입력하고 탭을 누르면 중복되는 이름이 없으므로 vi .bash_profile 명령어가 완성된다.

파일명에 대해 명령 완성

탭 완성 기능에 익숙해 지면 전체를 타이핑할 필요없이 빠르고 편리하게 해당 명령어를 실행할 수 있으므로 타이핑 실수도 줄이고 효율적으로 업무를 수행할 수 있다.

명령행 히스토리

커서표 키를 이용하여 호출했던 명령어를 다시 불러 낼 수 있다. 이 기능을 이용하여 예전에 입력한 명령어를 바로 호출하여 재사용할 수 있다.

긴 명령어를 입력하다가 중간에 오타가 나서 제대로 실행이 안 되었을 경우 처음부터 입력하지 않고 히스토리로 호출하여 오타난 부분만 수정하여 사용이 가능하다. 윗쪽 커서표 ↑ 는 이전 명령어를 호출하고 아래쪽 커서표 ↓는 예전 명령어 목록에서 이후 명령어를 호출할 경우에 사용한다.

만약 ls, last, ps 세 개 명령어를 순서대로 실행후 ↑ 를 한 번 누르면 마지막에 실행한 ps 가 호출되며 ↑ 를 또 누르면 last 가 호출된다. 이 상태에서 ↓를 누르면 last 의 이후 명령어인 ps가 호출되고 ↑ 를 누를 경우 last 의 이전 명령어인 ls 가 호출된다.


alias

bash에 내장된 명령어로 긴 명령어를 별명을 지정하여 사용할 수 있게 하는 기능이다. name=value 형식으로 지정할 수 있다.

다음 명령어로 vi 를 실행할 경우 vim 이 구동되게 할 수 있다.

$ alias vi='vim'


지정된 alias 를 해제하려면 unlias 명령어에 alias 명을 주어서 실행하면 된다. 다음 명령은 vi alias 를 해제한다.

unalias vi


옵션없이 alias 명령을 실행하면 -p 옵션을 붙인 것과 동일한 효과를 나타내며 이 경우 등록된 모든 alias 를 표시한다.

alias alias cp='cp -i' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'


중괄호 확장(brace expansion)

중괄호 확장은 bash 에만 있는 독특한 기능으로 임의의 문자열을 생성하고 이를 실행할 수 있는 기능으로 괄호를 기반으로 하여 명령어를 확대해 주므로 동일한 명령어를 비슷한 파라미터로 여러 번 호출해야 할 경우 매우 편리하게 사용할 수 있다.

문법은 중괄호안에 확장할 문자열을 콤마(,) 를 구분자로 하여 기술하며 중괄호 앞 뒤에는 치환되지 않는 패턴을 적어준다. 이해를 위해 간단한 예제를 살펴 보자.

만약 abf, acf, adf, aef 라는 문자를 echo 로 연속적으로 출력해야 할 필요가 있다고 가정해 보자. 여기에서 시작하는 'a' 문자와 마지막 'f' 문자는 고정되어 있고 중간에 한 가지 문자만 바뀌게 되므로 중괄호 확장 기능을 사용하여 간단하게 다음과 같이 기술할 수 있다.

$ echo a{b,c,d,e}f  

abf acf adf aef

한 경로 밑에 여러 개의 하위 디렉터리를 생성해야 하는 작업을 해야 한다고 가정해 보자. (후반에 기술하는 gitlab 이나 redmine 등 설치나 시스템 운영 작업시 이런 상황은 빈번하게 발생한다.)  
예로 /var/www/ 디렉터리 밑에 example.com 이라는 하위 디렉터리를 만들고 이 밑에 contents, logs, uploads 라는 세 개의 하위 디렉터리를 만들어야 할 경우 mkdir 을 사용한다면 최소 다음과 같이 세 번의 mkdir 명령을 수행해야 한다.

# mkdir -p /var/www/example.com/contents
# mkdir -p /var/www/example.com/logs
# mkdir -p /var/www/example.com/uploads

여러 번 mkdir 명령어를 실행하지 않고 brace expansion 기능을 활용하면 다음과 같이 한 번의 타이핑으로 괄호에 있는 세 개의 문자가 치환되어 mkdir 을 각각 세 번 실행한 것과 동일한 효과를 갖게 되므로 세 개의 디렉터리를 생성할 수 있다.

# mkdir -p /var/www/example.com/{contents,logs,uploads}

mkdir 실행시 -p 옵션을 주면 부모 디렉터리가 없을 경우 생성하게 된다.

그러므로 처음 명령어인 mkdir /var/www/example.com/contents 실행시 example.com 디렉토리가 없다면 생성하므로 먼저 example.com 을 생성할 필요가 없다.

for loop

명령어를 여러 번 실행할 때나 증가하는 패턴을 처리할 때 유용한 기능으로 for 구문뒤에 괄호로 {시작값..종료값..증가값} 을 써주고 루프를 돌 수 있다. 다음 예제는 1부터 10까지 2씩 증가하므로 총 다섯 번을 실행하게 된다.

for i in {1..10..2};do echo "Hello $i";done

마지막의 증가값은 생략해도 되므로 다음 예제는 열 번을 실행한다.

for i in {1..10};do echo "Hello $i";done


간단한 변수 export

쉘 스크립트나 설정 파일등에 설정한 내용을 전역적으로 읽으려면 export 키워드를 사용하여 전역 설정해야 한다. 기존 유닉스에서 사용하는 sh 는 export 시 다음과 같이 두 단계로 나눠서 설정해야 한다.

PATH=$PATH:/usr/local/bin
export PATH

bash 는 변수를 선언하면서 바로 export 명령을 적용할 수 있으므로 다음과 같이 간단하게 한 문장으로 사용할 수 있다.

export PATH=$PATH:/usr/local/bin


줄 편집(line-editing)

명령행 히스토리나 탭 완성같은 bash 만의 편리한 command line 능력은 readline 이라는 별도의 library 로 처리된다. 원래 readline 은 bash 의 일부였으나 워낙 유용하고 쓰임새가 많아서 별도의 라이브러리로 분리되어 관리되고 있다.

command 기반으로 동작하는 프로그램에 히스토리나 탭 완성 기능이 필요하면 readline library 를 사용하여 사용자 편의성을 높일수 있다. 대표적으로 MySQL DBMS 에 내장된 명령행 클라이언트인 mysql 명령도 readline 을 사용하고 있다. 


줄 편집 기능은 bash 의 명령줄을 편집할 수 쓸 수 있는 기능으로 익숙해지면 매우 효율적으로 작업할 수 있는 유용한 기능이다. 먼저 bash 에 기본 설정된 readline 명령과 매핑된 키보드 단축키는 bind -p 명령어로 볼 수 있다.



$ bind -p
"\C-a": beginning-of-line
"\C-e": end-of-line
"\C-r": reverse-search-history
...
단축키 확인

줄 편집은 많은 기능을 갖고 있지만 많이 쓰이고 유용한 기능과 단축키를 정리해 보면 다음과 같다. (전구) (\C는 Ctrl key, \e 는 Esc Key 이다)

Key
action
비고
\C-a line 의 처음으로 가기
\C-e line 의 끝으로 가기
\C-p예전 history로 가기키보드의 윗쪽 커서표 ↑ 동일 ("\e[A")
\C-n다음 history로 가기키보드의 아래쪽 커서표의 ↓동일("\e[B")
\C-rreverse increment search예전에 사용했던 명령어를 한 글자씩 치면서 찾을수 있음. 많은 명령어를 수행했을때 예전 명령어 호출시 유용
\e-uline의 문자를 대문자로 변경
\e-lline의 문자를 소문자로 변경
readline 의 주요 단축키 목록

이제 줄 편집 기능을 어떻게 사용하는지 알아 보자.  /etc 디렉터리에서 xml 파일중 내용에 UTF-8 이 들어가는 걸 찾아서 목록을 출력하는 다음 명령어가 있다.

    find /etc -name \*.xml -exec grep UTF-8 /dev/null {} \;

저 길고 복잡한 명령어를 치다가 실수로 find 대신 fond 라고 치고 실행하면 command not found 에러가 나고 실행이 되지 않을 것이다.

이제 sh 사용자는 저 긴 명령어를 처음부터 다시 쳐야 한다.

bash 사용자라면 위쪽 커서표로 오타낸 명령어를 불러내고 왼쪽 커서키로 커서를 오타난 부분까지 이동시켜 오타를 수정하고 재실행하면 된다.

하지만 줄 편집 기능을 사용하면 더 간단해진다. Ctrl-a 를 누르면 줄의 처음 부분으로 이동하므로 맨 앞의 f 에 위치하게 되며 우측 커서키를 한번만 누르면 바로 오타를 수정할 수 있다.

또 유용한 기능은 reverse increment search 기능이다.


역 점진 탐색(reverse increment search)

bash 의 히스토리는 HISTSIZE 환경 변수에 최대 저장할 수 있는 갯수가 지정되어 있고 기본값은 1,000 이다. 이제 복잡한 작업을 수행하느라 아주 많은 명령어(200개)를 실행했다고 하자. 그중에 하나는 위의 find 명령어인데 그 명령어를 재호출할 일이 생겼는데 그 명령어는 97번째에 앞에 실행했었다.

그럼 커서키를 97번을 눌러야 할까? reverse increment search 기능을 사용하면 순차적으로 원하는 명령어를 손쉽게 찾을 수 있다. 

  1. bash 프롬프트에서 Ctrl-r 키를 눌러서 다음과 같이 Reverse-i-search 모드로 들어간다.
  2. Prompt 가 없어지고 아래와 같이 입력창이 뜬다.

    (reverse-i-search)`':
  3. 순차적으로 찾으므로 한 글자를 입력할때 마다 해당하는 명령어를 보여준다. 다음처럼 fi 만 쳐도 예전에 수행했던 명령중 fi 있는 걸 표시한다.

    (reverse-i-search)`fi': find . -name \*xml
  4. 호출하고자 하는 예전 명령어와 일치할 때까지 나머지 명령어를 입력후 엔터를 쳐서 명령어를 수행한다.

환경 변수와 설정

설정 파일 처리 순서

bash 를 로그인 쉘로 사용할 경우 설정을 파일에서 읽게 된다. 설정 파일은 먼저 /etc/bashrc 파일의 설정을 읽고 안에 명령어가 있을 경우 실행하고 이후에 ~/.bashrc, ~/.bash_profile순서대로 처리한다.

사용자가 logout 할 경우 ~/.bash_logout 그리고 /etc/bash.bash_logout 파일이 있는지 확인하여 있을 경우 처리하게 된다. 일반적으로 ~/.bashrc 파일보다는 ~/.bash_profile 에 개인적인 내용을 설정한다.

설정 파일이 변경되었다면 source ~/.bash_profile 또는 . ~/.bash_profile 명령으로 설정 파일을 다시 읽어 들여야 현재 bash 에 반영된다. 


환경 변수

bash 는 여러 가지 환경 변수를 통해 동작을 제어할 수 있다.  그중에 꼭 알아두어야 할 환경 변수를 알아 보고 .bash_profile 에 설정해 보자


VISUAL

VISUAL  환경 변수는 사용할 편집기를 지정하는 환경 변수이다. 이 변수를 지정하면 편집기가 필요한 작업이 있을 경우 설정된 편집기를 사용할 수 있다.

예로 crontab 을 편집하거나 터미널에서 서브버전이나 git 등의 버전 관리 프로그램에서 커밋 메시지 작성등의 작업이 있다.

EDITOR 변수와 용도는 동일하나 EDITOR는 ed 같은 줄 기반의 편집기를 지정하고 vim 같은 기능이 많은 편집기는 VISUAL 변수로 지정하는게 일반적이다.

cron 프로그램이나 svn, git 등은 VISUAL 변수를 확인하고 없을 경우 EDITOR 변수를 찾는다.

설정 파일에 다음과 같이 지정하면 된다.

    export VISUAL=/usr/bin/vim


PS1

bash의 프롬프트 모양을 지정하는 변수이다. 기본 설정은 [\u@\h \W]\$ 이며 "사용자명@호스트명 작업디렉터리" 를 프롬프트에 표시하게 된다. 필자의 경우 다음 PS1 변수를 사용하는데 이럴 경우 컬러로 전체 경로를 표시하므로 가독성이 좋은 장점이 있다.

위에 있는 화면은 CentOS 기본 설정이며 아래에 있는 화면이 필자의 PS1 설정인데 이걸 사용할 독자들은 복잡하므로 직접 치지 말고 부록 소스를 참고하자.

프롬프트 설정


PATH

bash 가 실행 프로그램을 찾는 경로를 지정하는 환경 변수이다. 콜론(:) 으로 구분하여 여러 개를 설정 할 수 있다. 프로그램을 /usr/bin 이나 /usr/local/bin 같은 일반적이지 않은 경로에 설치했다면 해당 경로를 PATH 변수에 지정해 주어야 절대 경로를 입력하지 않고 사용할 수 있다.

설정 파일에 PATH 추가시 기존 PATH 변수를 적어주고 그 뒤에 추가할 PATH 를 적어주면 된다.

    export PATH=$PATH:/opt/myprog/bin


LD_LIBRARY_PATH

정확히는 bash 가 사용하는 변수는 아니고 리눅스의 프로그램 로더(loader) 인 ld.so 가 참고하는 변수이다. 프로그램 실행에 필요한 동적 라이브러리(확장자 .so) 를 찾는 경로이며 이 경로에 라이브러리가 없다면 프로그램 실행에 실패한다.

프로그램 설치시 동적 라이브러리가 같이 설치됐는데 /lib, /usr/lib, /usr/local/lib 같이 일반적인 경로가 아닐 경우에는 이 환경 변수를 설정해야 한다. 


LANG

어떤 로캘(locale) 을 사용할 지 설정하는 변수이다. 설치 언어를 한글로 했으면 기본 로캘은 ko_KR.UTF-8 가 된다. 이 경우 프로그램이 다개국어를 지원하고 한글 번역이 있을 경우 메시지가 한글로 표시되며 man 으로 보는 시스템 매뉴얼 페이지, 기타 에러 메시지등이 한글로 표시된다.

혹시 터미널 설정이 잘못 되었거나 한글을 출력할 수 없는 터미널이거나 등의 이유로 한글이 깨지면 로캘을 다른 언어로 설정해 주면 된다.

로캘은 표시 언어(LC_MESSAGES)외에 화폐 표시(LC_MONETARY), 숫자 표시(LC_NUMERIC), 시간대(LC_TIME) 등 개별 설정 변수가 각각 있으므로 표시 언어만 다른 언어로 변경할 수 있다.

다음과 같이 설정하면 표시 언어만 영어로 설정된다.

    export LC_MESSAGES=en_US.utf8

LANG 변수에 설정하는 것은 로캘 관련 개별 변수를 한 번에 설정하기 위한 변수이므로 전체 로캘을 변경할 경우 다음처럼 LANG 변수를 설정하면 된다.

    export LANG=en_US.utf8

현재 설정된 로캘은 locale 명령을 실행하면 알 수 있다.