유닉스를 능숙하게 사용하기: 몇 번만 클릭하자

전문가처럼 명령행 편집하기

컴퓨터와 인터페이스하는 방식은 끊임없이 변화하고 있습니다. 한 때 명령행 인터페이스만 제공했던 운영체제는 그래픽 프론트엔드로 이동해왔습니다. 하지만 운영체제를 위대하게 만든 원천에서 벗어난 결과가 항상 올바른 방향을 지향했다고 보기는 어렵습니다. IBM?? AIX?? 운영체제는 안정성, 기능성, 견고성이라는 가장 중요한 철학을 지키고 있습니다. 강력한 명령행 인터페이스(CLI, Command Line Interface)를 유지하는 방법으로 AIX는 이런 철학을 지켜왔습니다. CLI 사용법을 배운 적이 없거나 기초를 다시 한번 되새김질할 필요가 있다면 이 기사를 읽어보기 바랍니다.

컴퓨터와 인터페이스하는 방식은 끊임없이 변화하고 있다. 한 때 명령행 인터페이스로 시작했던 운영체제는 그래픽 프론트엔드로 이동했다. 하지만 종종 운영체제를 구성하는 블록에서 벗어난 결과가 항상 올바른 방향을 지향했다고 보기는 어렵다. 종종 그래픽 사용자 인터페이스(GUI) 이동은 기능 상실을 의미한다. 또한 사용자는 작업 대상 컴퓨터에 대해 뭔가 더 익히기를 꺼려하는 경향이 있다. 다행히도 AIX 운영체제는 다른 유닉스(UNIX??)/리눅스(Linux??) 시스템과 마찬가지로 컴퓨터 운영체제에서 안정성, 기능성, 견고성이라는 가장 중요한 철학을 지켜왔다.

다양한 유닉스와 리눅스 회사는 운영체제의 CLI 이면에 숨겨진 중요성을 확실히 깨닫고 있다. 자동화, 사용자를 위한 작업 편의성 등의 이유 때문에 사용자는 CLI라는 복잡한 도구를 잊어버렸거나 결코 배우지 않으려고 한다. 이 기사에서는 CLI에 익숙하지 않은 사용자와 관리, 개발, 일반 유닉스 컴퓨팅에 CLI가 중요한 이유를 기억하기 위해 주의 환기가 필요한 사용자를 위해 CLI를 설명한다.

명령행이 무엇인가?

컴퓨터로 작업할 때, 실제로 어디서 작업하는지를 이해해야 한다. 유닉스나 리눅스에서 작업해봤다면, 셸이나 명령행이라는 용어를 분명히 들어봤을 것이다. 두 용어는 같은 뜻으로 사용될 수 있으며, 현재 사용 중인 실제 유닉스 셸을 지칭한다. 유닉스에서 셸이라는 용어는 명령어를 입력하거나 기능을 수행하기 위해 사용하는 인터페이스를 지칭한다.

사용자가 콘솔이나 네트워크를 통해 유닉스 시스템에 로그인하면, (/etc/passwd에서) 정의한 셸이 떠서 사용자 환경이 환경 설정 파일을 통해 설정되면(이 기사 후반부에 다룬다), 사용자는 셸에서 명령을 수행할 준비가 끝난다. 사용자가 셸을 통해 명령어를 명령행에서 입력할 때, 사용자는 사용자나 프로그램이 제공하는 입력 수단인 표준 입력(stdin)만 볼 수 있다. 사용자가 엔터나 리턴을 누르면, stdin은 실행을 위해 셸로 보내지며, 사용자는 표준 출력(stdout)이나 표준 오류(stderr)를 통해 결과를 받는다. 표준 출력이나 표준 오류는 결과 방향을 지정하는 상황에 따라 달라진다(예: 사용자 화면, 파일, 프린터). stdout이라는 용어는 실행된 프로그램이 돌려주는 출력 자료를 의미하며, stderr은 프로그램 실행 도중이나 완료 후에 일어난 오류를 의미한다. 사용자는 하나 또는 여러 명령을 처리하는 과정에서 모든 저수준 코드 수행 결과를 보지 못하며 아주 간략화된 입력, 출력, 오류만 볼 수 있다. 이런 이유 때문에, 사용자가 정상으로 로그인해 실행한 프로그램은 셸을 부른다. 셀은 운영체제에서 제공하는 저수준 호출을 남김없이 감추기 때문이다.



셸의 역사

유닉스 셸은 진화와 발전을 거치며 대략 35년 동안 사용되어 왔으며, 여전히 기세가 꺾이지 않고 있다. 1971년에 셸은 AT&T 벨 연구소에 근무하던 켄 톰슨이 첫 번째 유닉스 셸인 톰슨 셸을 만들면서 세상에 등장했다. 자료 방향 재지정과 같은 톰슨 셸이 제공하는 기본 기능은 오늘날까지도 셸에 존재한다. 물론 톰슨 셸은 파이프( | ), 셸 스크립트 기능, if 조건문과 같은 오늘날 유닉스 사용자가 매일 사용하는 몇몇 중요한 내장 기능이 빠져있다.

이런 결과로 인해 톰슨 셸은 1977년에 보른 셸(sh)로 대체된다. AT&T 벨 연구소에 근무하던 스티븐 보른이 만든 보른 셸은 유닉스 버전 7(V7)을 위한 기본 셸이 된다. 보른 셸은 유닉스의 미래로 한 걸음 크게 내디뎠다. 보른 셸 덕택으로 사용자는 셸 스크립트를 작성할 수 있었으며, 변수에 정보를 저장하고 공개하며, 파일 기술자를 제어하고 신호 처리를 제어하고 for 반복문과 case 문과 같은 구문을 활용할 수 있었다. 심지어 보른 셸이 만들어진 지 30년이 지났지만 여러 현존하는 유닉스 시스템에 탑재되어 있으며, 오늘날 여러 유닉스 시스템에서는 슈퍼유저(즉 root)를 위한 기본 셸로 지정되어 있다.

지난 30년 동안, 유닉스 셸에는 변경과 개선이 있었다.이런 결과로 여러 가지 셸이 만들어졌다. 그림 1 은 몇몇 유닉스 셸의 가계도를 보여준다. 그림이 완벽하지는 않지만, 주요 셸과 여기서 파생된 셸 사이에 연결 관계를 보여준다.


그림 1. 유닉스 셸 가계도





콘 셸

콘 셸(ksh)은 1982년 AT&T 벨 연구소에 근무하던 데이비드 콘이 처음 개발했다. 다른 셸과 마찬가지로 콘 셸은 보른 셸(sh)과 하위 호환성을 유지하며, 25년이라는 경험을 토대로 튼튼하고 안정적이고 신뢰할 만한 셸로 발전을 거듭해왔다. IBM은 콘 셀을 AIX의 기본 셸로 사용한다. 콘 셸에는 버전이 두 가지가 있으며, AIX는 둘 다를 포함한다.

AIX에서 일반 사용자를 위한 첫 번째이자 기본 셸은 표준 ksh이다. 콘 셸은 운영체제의 국제적인 표준인 POSIX(Portable Operating System Interface for Computer Environments)를 따른다.

AIX에서 사용할 수 있는 두 번째 콘 셸은 개선된 콘 셸로 ksh93으로 부른다. 표준 콘 셸에 여러 가지 멋진 기능을 추가한 ksh93은 다음과 같은 기능을 포함한다.

  • 수학 연산 개선
  • 복합 변수
  • 복합 대입
  • 연상 배열
  • 변수 이름 참조
  • 매개 변수 확장
  • 특정 변수에 결합된 함수
  • 함수 환경 지정
  • PATH 검색 규칙
  • 셸 히스토리
  • 추가 내장 명령어

ksh로 명령행 환경 설정하기

ksh로 명령행을 편집하는 방법을 살펴보기 전에 환경을 설정해야 한다. 개인 기호에 따라 콘 셸을 설정하는 방법은 상대적으로 간단하다. ksh로 로그인했다면 set 명령어에 -o 스위치를 붙여 현재 설정 상태를 확인하자.


# set -o

Current option settings are:
allexport off
bgnice on
emacs off
errexit off
gmacs off
ignoreeof on
interactive on
keyword off
markdirs off
monitor on
noexec off
noclobber off
noglob off
nolog off
notify off
nounset off
privileged off
restricted off
trackall off
verbose off
vi off
viraw on


각 설정값에 대한 간략한 설명을 정리했다( man set 으로 세부 설명을 찾아볼 수 있다).

  • allexport : 지금부터 정의된 모든 변수를 자동으로 외부에 공개한다.
  • bgnice : 배경에서 동작하는 모든 프로세스를 더 낮은 우선 순위로 돌린다.
  • emacs : 입력한 명령행 텍스트를 편집할 때, emacs 스타일 인라인 편집기를 사용한다.
  • errexit : 명령어가 0이 아닌 다른 종료 상태로 끝나면, ERR 트랩을 수행한다(물론 이 트랩이 설정되었으며 존재할 경우에만).
  • gmacs : 입력한 명령행 텍스트를 편집할 때, gmacs 스타일 인라인 편집기를 사용한다.
  • ignoreeof : EOF 문자를 무시하고 셸을 끝내지 않는다. 사용자가 종료를 원하면 exit 명령어를 입력하거나 컨트롤-D를 11번 누른다.
  • keyword : 명령어 앞에 오는 인수뿐만 아니라 명령어 중간에 나오는 모든 변수 대입 구문도 인식한다.
  • markdirs : 파일 이름 대체 과정에서 순 방향 슬래시( / )를 디렉터리 끝에 붙인다.
  • monitor : 모든 작업을 별도 프로세스로 배경에서 수행하며, 프로세스가 끝나면 stdout으로 출력하는 방법으로 사용자에게 결과를 알린다.
  • noexec : 명령을 수행하지 않는다. 대신 구문 오류만 검사한다.

    주의 : 비활성 셸에서 시도할 경우 이 옵션은 무시된다.

  • noclobber : 이 플래그는 출력 방향 지정을 바꿀 때 현존하는 파일을 잘라버리지 못하도록 막는다. 이 옵션을 켜더라도, > 와 파이프 기호( >| )를 사용하면 파일을 잘라버릴 수 있다.
  • noglob : 파일 이름 치환 기능을 비활성화한다.
  • nolog : 이 옵션을 켜면, 히스토리 파일에 함수 정의가 저장되지 않는다.
  • nounset : 치환 과정에서 설정되지 않은 모든 매개변수는 오류로 반환된다.
  • restricted : 제약이 가해진 셸을 수행한다. 사용자는 디렉터리를 변경하지 못하며 SHELL, ENV, PATH 변수도 변경하지 못하며 경로 이름에 선행 슬래시 문자( / )가 들어있는 명령어도 수행하지 못하며 출력 방향 재지정도 불가능하다.
  • trackall : 각 명령을 처음 수행할 때 경로를 기억해 다음 번 수행 속력을 높이는 추적 앨리어스로 기록한다.
  • verbose : 모든 입력 행 내용을 셸이 읽은 그대로(즉 확장하지 않고) stdout으로 출력한다.
  • vi : 입력한 명령행 텍스트를 편집할 때, vi 스타일 인라인 편집기를 사용한다.
  • viraw : 입력하는 각 문자를 마치 vi 편집기에서 입력한 듯이 수행한다.
  • xtrace : 실행되는 모든 명령어와 인수를 표준 출력으로 내보낸다(즉 확장한 상태로).

내장 명령어 집합에서 옵션을 켜려면 -o 스위치를 사용하자. 마음이 바뀌면 -o 대신 +o 스위치를 사용해 설정한 옵션을 끌 수 있다.

이 기사에서 초점을 맞추는 핵심 옵션은 인라인 편집기 스위치다. 사람마다 vi, emacs, gmacs 편집기 중 하나를 선호한다. 콘 셸은 세 가지 편집기 모두를 수용한다. 하지만 이 기사에서는 vi 편집기에 초점을 맞춘다. 인라인 편집기 옵션을 vi 로 설정하기는 쉽다. 현재 설정을 보기 위해 사용했던 명령어에 다음과 같이 옵션을 입력하기만 하면 된다.


# set -o vi


이제 끝났다. 설정 값을 비교하려면 다시 한번 현재 설정을 살펴본다.

# set -o

Current option settings are:
allexport off
bgnice on
emacs off
errexit off
gmacs off
ignoreeof on
interactive on
keyword off
markdirs off
monitor on
noexec off
noclobber off
noglob off
nolog off
notify off
nounset off
privileged off
restricted off
trackall off
verbose off
vi on
viraw on
xtrace off




콘 셸 vi 인라인 편집기 활용하기

이제 vi 인라인 편집기를 사용하도록 셸을 설정했으므로, 테스트할 시간이 왔다.

명령행에서 텍스트 변경하기

지금 명령행에 글자를 입력하면서 vi 편집기에서 삽입 모드에 들어와 있다고 생각하기 바란다. 실수를 하거나 실행할 명령어에 뭔가를 추가할 필요가 있다면, ESC 키를 누르고 삽입 모드를 빠져나가 명령 모드로 돌아간다.

예를 들어, 현재 작업 디렉터리 내용이 다음과 같다고 가정하자.

# ls
fileA fileAA fileAAA fileAB fileABA fileABB fileB fileBAA fileBB fileBBB


fileAA로 시작하는 파일을 찾아 삭제하기를 원한다면 다음과 같은 명령을 내린다.

# find . -name "fileAB*" -exec rm {} \;

입력한 행을 수행하기 전에, fileAA 대신에 fileAB 를 입력했다는 실수를 찾았다! 걱정할 필요 없다. 삽입 모드에서 빠져나와서 명령 모드로 들어가서 잘못된 글자로 커서를 옮기고 글자를 바꾸자. 이 모든 작업은 vi 명령으로 수행한다. 인라인 편집기에서 삽입 모드에 들어있는 상태에서 명령 순서를 차례로 쪼개보자.

  1. ESC를 눌러 명령 모드로 전환한다.
  2. vi 스타일 이동 명령(H키는 커서를 왼쪽으로 움직인다)을 사용해 문자열 "fileAB*"에서 B로 커서를 이동한다.

    주의 : vi에서 화살표 키에 익숙하다면 커서를 움직이는 과정에서 키보드의 어떤 키를 누르는지 익혀두는 편이 현명하다. TERM 유형이 달라 화살표 키로 원하는 결과를 얻지 못할 가능성이 있기 때문이다.

    • h : 왼쪽
    • l : 오른쪽
    • k : 위쪽
    • j : 아래쪽
  3. vi 스타일로 '한 글자 변경' 명령을 사용해 B를 A로 바꾼다(다시 말해, R을 누른 다음에 A 를 입력한다).

작업을 검토해 원하는 결과를 얻었다면 명령어를 수행하기 위해 엔터를 누르자.

# find . -name "fileAA*" -exec rm {} \;
# ls
fileA fileAB fileABA fileABB fileB fileBAA fileBB fileBBB

파일 이름 완성

콘 셸에서 vi 인라인 편집기를 유용하게 사용하는 또 다른 방법은 파일 이름 완성이다. 명령어를 수행할 때, 종종 stdin이나 stdout(또는 stderr) 내용을 파일에 쓰기 위해 매개변수로 사용할 파일을 입력하는 경우가 있다. 파일 이름이 길고, 비슷한 이름이 여러 개 존재하거나 전체 파일 이름을 기억하지 못한 경우가 있다. 이럴 때가 바로 파일 이름 완성 기능이 도움을 주는 상황이다. 파일 이름을 입력할 때, 절반 정도 진행한 다음에 ESC키를 누른 다음에 \ (역슬래시)를 누르면 된다. 이런 방법은 편리할 뿐만 아니라 시간도 상당히 절약해준다.

예를 들어, AIX에서 /etc/filesystems를 보기를 원했는데, 전체 파일 이름을 잊어버렸다. /etc에 있다는 사실을 알고 파일 이름이 무엇으로 시작하는지도 알지만 그게 전부다. 단순히 view /etc/file 을 입력하고 ESC-\를 누르면 만세! ksh이 대신해 행을 완성해준다. 명령행에는 view /etc/filesystems 라는 완성된 내용이 적혀 있다.

디렉터리 구조에서도 똑같은 작업이 가능하다. 디렉터리 이름도 파일 이름과 동일하게 취급하기 때문이다.

명령어 히스토리 확인과 변경

유닉스 시스템에서 프로세스를 감시하거나 다른 기능을 수행하는 과정에서 동일한 명령을 계속해서 입력한 경우가 있는가? 매번 다시 입력하는 대신에 콘 셸은 검토를 위한 내장 명령어 히스토리 기능을 제공한다. 인라인 편집기를 vi 로 설정하면, ksh은 사용자가 수행한 명령어 히스토리를 꺼내 명령행에 입력한 다른 텍스트로 변경하는 기능을 지원한다. 시스템 설정에 따라 해당 세션만 기억할 수도 있다.

변수 HISTFILE에 파일 이름을 정의했다면, ksh은 히스토리에서 끄집어내어 원본 명령어를 다시 수행하거나 명령을 수정할 기회를 제공한다. 예를 들어, 여기에 예제 $HISTFILE에서 마지막으로 실행한 명령 열 개를 뽑았다.

# tail -10 $HISTFILE
ls
cd ~cormany/testdir/dirA
./fileA 1>fileA.out 2>fileA.errors
pwd
ps --fu cormany
df --k .
ps --fu cormany
find . --name “fileA.out” --ls
find . --name “fileA.errors” --ls
tail -10 $HISTFILE

명령행에 있을 때 vi 인라인 편집기에서 명령행 모드로 들어가려면 ESC만 누르면 된다. 그리고 나서 K를 눌러 마지막으로 수행한 명령을 끌어내자. 여전히 명령 모드에 있기 때문에 K를 계속해서 눌러 명령어 히스토리 하나 위로 가거나 J를 눌러 명령어 히스토리 하나 아래로 갈 수 있다.

명령 모드 커서 이동을 간편하게 기억하기 위해, 명령행 프롬프트에서 ESC를 누를 때, vi에서 일반 파일로 $HISTFILE을 읽었다고 생각하자. vi 편집기에서 K키는 한 행 위로 올라가고, J키는 한 행 아래로 내려간다. 동일한 $HISTFILE에서 ESC-J를 누르면 $HISTFILE 편집 과정을 시각적으로 보여주며 파일의 아래쪽에 커서가 위치한다. 행은 tail -10 $HISTFILE 이 될 것이다. J를 다시 한번 누르면 편집 중인 $HISTFILE에서 한 행 올라가 행은 find . -name "fileA.errors" --ls 가 될 것이다.

그림 2 는 ksh vi 인라인 편집기 명령 모드 움직임을 일반 vi 명령 모드 커서 움직임과 비교한 간단한 "커닝 페이퍼"를 보여준다.


그림 2. vi 명령 모드 커닝 페이퍼





명령행 vs 셸 스크립트

셸 스크립트를 사용해야 하는 경우가 있고, 명령행을 사용해야 하는 경우가 있다. 주기적으로 반복해서 작업을 수행하거나 항상 사용자에게 명령을 입력하게 만드는 대신 자료 처리를 요구하는 등 요청 작업이 복잡하다면 셸 스크립트가 유용하다. 그렇지 않고 한번만 명령을 사용하거나 상대적으로 간단한 명령을 수행할 경우 명령행으로 간단하게 작업을 처리할 수 있다.

예를 들어, 이 디렉터리 목록을 살펴보자.

# ls
fileA.tar.gz fileAA.tar.gz fileB.tar.gz fileBB.tar.gz

단순히 파일 압축을 해제한 다음에 bzip2로 다시 압축하고 ATC-AIX2로 전송하기를 원한다면 셸 스크립트를 작성하는 대신에 명령행으로 처리할 수 있다. 셸 스크립트를 여러 명령행 항목을 한번에 입력하는 방법으로 생각하자. 상식적으로 셸 스크립트가 정말로 의미하는 바를 제대로 나타내기 때문이다. 명령행에서 명령어를 입력할 때, 이런 작업은 스크립트에 명령어를 입력한 다음에 이 스크립트를 수행하는 경우와 똑같다.

디렉터리를 돌며 gz로 끝나는 파일만 찾아 압축을 해제한 다음에 bzip2로 다시 압축하고 scp 명령으로 파일을 ATC-AIX라는 목적지 서버로 옮기기를 원한다. 반복은 스크립트와 마찬가지로 명령행에서도 멋지게 동작한다. loop...if 조건문, case switch 문, 기타 코드 블록 문을 시작할 때 동작 중인 ksh은 단순히 커서를 다음 행으로 내리고 프롬프트를 $PS2로 바꿀 것이다. 코드 블록이 완료되면, 코드 블록을 수행하고 사용자에게 $PS1 프롬프트를 보여준다.

다시 정리하면 다음과 같다.

  • $PS1 프롬프트 : 다음 명령어를 기다림
  • $PS1 프롬프트 : 코드 블록 시작
  • $PS2 프롬프트 : 코드 블록 계속
  • $PS2 프롬프트 : 코드 블록 계속
  • $PS2 프롬프트 : 코드 블록 끝
  • 코드 블록 수행
  • $PS1 프롬프트 : 다음 명령어를 기다림

변수 PS2의 기본값은 > 이다. 압축을 풀고 다시 압축하는 직전 예제로 돌아가서, ksh 명령행에서 다음과 같이 간단하게 입력할 수 있다.


# for _FNAME in 'ls -1 *.gz'
> do
> gzip -d ${_FNAME}
> bzip2 ${_FNAME%*.gz}
> scp ${_FNAME%*.gz}.bz2 cormany@ATC-AIX2:/home/cormany
> done


코드 블록을 끝낸 다음에(다시 말해 done 으로 반복을 종료한 다음에) 엔터를 누르면 반복을 시작한다. 명령행에서 입력한 반복은 .gz로 끝나는 모든 파일을 현재 디렉터리에서 찾은 다음에 압축을 풀어 bzip2로 다시 압축하며, ATC-AIX2에 있는 /home/cormany 디렉터리로 전송한다. 아주 간단하다.




결론

이 기사를 읽고 나면, 예전에 몰랐던 콘 셸 활용법을 이해할 것이다. 명령행을 완벽하게 터득하면 작업을 단순하게 만들 수 있으며, 셸과 명령행에 질질 끌려다니는 대신에 앞서나가기 위한 방법을 제대로 이해하는 데 도움이 된다.

필자소개

Adam Cormany는 National Data Center의 관리자로 현재 일하고 있다. Cormany는 유닉스 시스템 엔지니어, 유닉스 관리자, Scientific Games Corporation에서 운영 관리자를 맡아왔다. Cormany는 10년 넘게 솔라리스, 레드햇 리눅스 관리자는 물론이고 AIX도 광범위하게 다뤘다. Cormany는 pSeries AIX 시스템 관리 분야에서 IBM eServer?? 공인 전문가다. 관리 업무 이외에, Cormany는 배시, csh, ksh을 사용한 셸 스크립트와 C, PHP, 펄 프로그래밍에도 광범위한 지식을 습득했다.

제공 : DB포탈사이트 DBguide.net

+ Recent posts