bash 기초-1
bash 기초
shell 이란
- Application을 실행시키는 도구
- 물론 shell도 애플리케이션의 일종
- OS의 커널에 직접 접근할 수 없기 때문에 명령어 해석기인 셸이 필요
-
Shell에서 내리는 명령어는 해석된 뒤에 자식 프로세스로 만들어져 실행된다. 실행된 프로세스는 시스템(커널)이 관리하게 된다.
shell 의 역사
- Bourne shell :
/bin/sh
- C shell :
/bin/csh
- Korn shell :
/bin/ksh
- bash :
/bin/bash
- Zsh :
/bin/zsh
- 본셸
/bin/sh
- 스티븐 본이 작성 , 1977 , POSIX shell
- 유닉스는 본셸을 꼭 갖고 있어야함
- 씨셸
/bin/csh
- 빌조이, BSD UNIX
- C 언어와 비슷한 문법으로 인해 C shell 로명명
- 호환성 문제 발생
-
콘셸
/bin/ksh
- 벨랩. 데이비드 콘
- csh, tcsh 기능 포함
- vi prompt mode 지원
- 배시셸
/bin/bash
- Korn 벤치 마킹
- GNU/Linux , Mac OSX 계열에서 기본 셸로 사용
Mac OSX는 2019 부터 zsh 사용
- 지셸
- 커스터 마이징 다양
- 예쁘고 편리한 플러그인 추가가 쉽다.
특수문자 읽는 방법
prompt input mdoe
- vi :
set -o vi
- emacs mode
set -o emacs
- bash 에서 명령어 한줄 한줄치는것 자체가 명령어가 담긴 텍스트 파일을 편집해서 저장하는것으로할 수 있다.
파일은 history에 저장된다고 할수 있겠다한줄 한줄 치는것의 편집기는 emacs를 사용한다. -
emacs edting mode
요즘은 clear말고 ^(ctrl)L을 한다고 하더라… - vi edting mode
- j,k : 명령어 히슽리 라인의 이동 아래로 1줄, 위로 1줄
- #G : 히스토리에서 #번째 명령어 싫앵
- TAB : command-completion 기능
- = : 매칭된 파일 이름 출력
- recall command line args
- 상황을 떠올려 보자. 내가
curl <url1> <url2> ...
을 했는데 이<urln>
만 다시 가져오고 싶다. - 그때
![i]:n
을 써보자- i 번째 히스토리 명령어의 n-th argument (i 생략시 previous command)
!:n-m
: 이전 명령어의 n~m 인자리스트를 불러온다.- 더 쉬운 단축키로는
ALT
+.
을 누르자. 그러면 인자 하나씩 하나씩 불러온다.
- 상황을 떠올려 보자. 내가
shell vs sub-shell
- 셸에서 실행되는 UNIX 명령어는 sub-shell이 생성되어 실행
- 서브셸이란
fork-exe
로 만들어지는 child-process 셸이다. - 외부 명령어 실행은 기본적으로 서브 셸을 생성하므로 process 생성의 overhead가 존재한다.
ls -al
이라는 명령을 싫앻나다면 원래의 셀이 포크해서 자식 프로세스가 생기고 자식은 부모를 복제한다. 이를 서브 셸이라고 한다. 그러고 나서 ls를 실행하기 위해exec
명령을 실행한다. 실행이 끝나면 부모에게 exit code 를 반환한다.
- 다음 작업을 진행하기위해 자식의 프로세스의 exit code를 받아야한다. ( true : 0 , else : false)
obo@obo-900X3L:~$ touch qwer obo@obo-900X3L:~$ rm qwer obo@obo-900X3L:~$ echo $? 0 obo@obo-900X3L:~$ rm qwer rm: cannot remove 'qwer': No such file or directory obo@obo-900X3L:~$ echo $? 1 obo@obo-900X3L:~$
- 서브셸이란
rm --force
에 대한 오해
rm -rf
- UNIX command, 특히 rm 과 같은 optional한 기능에
--force
옵션이 존재하는 것은 child process로 작동할 때exit code
를 조작하기 위함이다. - 즉 shell script 처리를 위해서 존재하는 기능들이다.
-
예로 어떤 파일을 삭제하려는데, 예를 들어서 쓰레기 파일들을 프로세스가 다 종류된다음에 다 청소를해야하는데, 생성될수도 안될 수도 있다. 그래서, 무조건 리턴값을 무시한다. 삭제할 때 없어도 리턴값은 0이 나올것이다.
obo@obo-900X3L:~$ rm -f qwer obo@obo-900X3L:~$ echo $? 0 obo@obo-900X3L:~$
systemctl
- 시스템 가동 관련 정보들을 감시하는 서비스..
- sysstat unit으로 테스트해보자.
- 시작 :
systemctl enable --now sysstat
Variables
변수 선언
[set] name=value
name
이라는 변수에value
선언 또는 변경=
사이에 공백은 허용되지 않는다.
변수 expression
${name}
{}
중괄호 생략 가능, 명확하게 변수명이 구별 가능한 경우에 생략
변수 removal
unset <name>
white space
- 셸 프로그래밍 문법에서 공백의 역할
- 공백은 셸 프로그래밍에서 특별한 역할을 하는경우가 있다.
- 변수와 연산자를 구별하기 위한 역할
- 셸 명령어 토큰 처리를 위한 구분 역할
- 프로그래밍 언어의 블록 구분 = { } 의 역할
- 공백을 임의로 생략하거나 넣으면 오류가 발생한다
- 공백은 셸 프로그래밍에서 특별한 역할을 하는경우가 있다.
-
공백이 중요한 예
obo@obo-900X3L:~$ var1="helloobo" obo@obo-900X3L:~$ echo $var1 helloobo obo@obo-900X3L:~$ var1 = "happyOBO" var1: command not found
environment variable
- 환경 변수
- 셸 변수에 상속 속성을 설정 -> fork하는 경우 child process에 상속됨
- 환경 변수 declaration
export <NAME>=<CONTENTS>
또는declare -x <NAME>=<CONTENTS>
- 환경 변수 expression
- 일반 변수와 동일
-
built in env. var
obo@obo-900X3L:~$ env LC_PAPER=ko_KR.UTF-8 XDG_SESSION_ID=10 LC_ADDRESS=ko_KR.UTF-8 LC_MONETARY=ko_KR.UTF-8 TERM=xterm-256color SHELL=/bin/bash ROS_ROOT=/opt/ros/kinetic/share/ros SSH_CLIENT=127.0.0.1 33984 22 ROS_PACKAGE_PATH=/opt/ros/kinetic/share ROS_MASTER_URI=http://localhost:11311 LC_NUMERIC=ko_KR.UTF-8 ROS_PYTHON_VERSION=2 OLDPWD=/home/obo/42dot ... PKG_CONFIG_PATH=/opt/ros/kinetic/lib/pkgconfig:/opt/ros/kinetic/lib/x86_64-linux-gnu/pkgconfig LESSOPEN=| /usr/bin/lesspipe %s CMAKE_PREFIX_PATH=/opt/ros/kinetic XDG_RUNTIME_DIR=/run/user/1000 LESSCLOSE=/usr/bin/lesspipe %s %s LC_TIME=ko_KR.UTF-8 SCENARIO_RUNNER_ROOT=/home/obo/42dot/scenario_runner ROS_ETC_DIR=/opt/ros/kinetic/etc/ros LC_NAME=ko_KR.UTF-8_=/usr/bin/env
- 환경변수 PATH
- 명령어를 탐색하는 기능
- 사실은
ls
를 실행할때 PATH라는곳에 디렉토리를 다 뒤지면서/bin/
에 있네?/bin/
에서ls
를 실행한다.
# ~/.bashrc export PATH=~/develpment/sdk/bin:$PATH ## 이렇게 선언하면 PATH 가 계속적으로 늘어나서 나중엔 엉망이 된다...!
- 그러면 어떻게 하나..!
pathmunge
라는 셸 함수를 만들어서 사용한다.- 기존에 이 PATH가 있으면 추가하지 않고, 없으면 추가해준다..!
if [ "$(type -t pathmunge)" != 'function' ]; then pathmunge () { [ ! -d "$1" ] && return 1 case ":${PATH}:" in *:"$1":*) # 있으면 pass ;; *) # 없으면 추가 if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi esac } fi pathmunge $HOME/devel/sdk/bin after