@ 08_리눅스 쉘
- 리눅스 사용자와 커널 사이에서 동작하는 인터페이스 역할을 담당하는 프로그램이다.
- 리눅스 사용자가 실행한 명령어를 해석하여 커널에게 전달하는 역할을 수행하기 때문에 명령어 해석기라고 한다.
1. 쉘 기능
- 입력을 읽고 해당 명령행을 분석하여 커널에게 전달한다.
[root@Client1 /root]# ls -l /root
합계 8
-rw-------. 1 root root 1360 2022-03-24 16:25 anaconda-ks.cfg
-rw-r--r--. 1 root root 1732 2022-03-24 16:44 initial-setup-ks.cfg
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 공개
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 다운로드
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 문서
drwxr-xr-x. 2 root root 40 2022-03-24 17:01 바탕화면
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 비디오
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 사진
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 서식
drwxr-xr-x. 2 root root 6 2022-03-24 16:57 음악
- 특수 문자를 분석하여 커널에게 전달한다.
[root@Client1 /root]# ls -l /etc/*.conf
-rw-r--r--. 1 root root 55 2021-12-23 14:04 /etc/asound.conf
-rw-r--r--. 1 root root 25696 2020-10-27 05:16 /etc/brltty.conf
-rw-r--r--. 1 root root 1085 2021-06-24 23:21 /etc/chrony.conf
-rw-r--r--. 1 root root 1174 2020-12-15 16:23 /etc/dleyna-server
~ 중간 생략 ~
- 파이프, 리다이렉션, 백그라운드 프로세스를 처리한다.
[root@Client1 /root]# ls -l /etc/*.conf | grep resolv > nameserver.txt
[root@Client1 /root]# ls -l nameserver.txt
-rw-r--r--. 1 root root 67 2022-03-26 11:26 nameserver.txt
[root@Client1 /root]# cat nameserver.txt
-rw-r--r--. 1 root root 54 2022-03-26 11:16 /etc/resolv.conf
[root@Client1 /root]# rm -rf nameserver.txt
2. 쉘 유형
3. 쉘 관련 사용자 환경 파일
1. profile
2. profile.d
3. .bash*
4. bashrc
1) 계정 로그인 및 쉘이 실행될 때 다음과 같은 순서대로 해당 파일들이 읽혀진다.
- 관리자가 일반 사용자의 환경을 설정 시켜 주는 경우
/etc/profile : 로그인 할 때만 읽혀짐
/etc/bashrc : 쉘이 실행 될때 마다 읽혀짐
/etc/profile.d/*.sh : 쉘이 실행 될때 마다 읽혀짐
- 일반 사용자가 자신의 환경을 설정 하는 경우
$HOME/.bash_profile : 로그인 할 때만 읽혀짐
$HOME/.bashrc : 쉘이 실행 될때 마다 읽혀짐
|─────────로그인──────────|──────쉘 실행 ──────|
/etc/profile -> $HOME/.bash_profile -> $HOME/.bashrc -> /etc/bashrc
/etc/profile.d/*.sh
① ② ③ ④
- ① : 시스템을 사용하는데 필요한 환경 변수 내용(모든 사용자에 적용되는 내용)들이 설정되어 있다. (cat /etc/profile)
- ② : 계정이 필요한 환경 변수 내용(해당 계정에만 적용되는 내용)들이 설정되어 있다. 로그인 관련 배너 설정을 할 수 있다. (cat /root/.bash_profile)
- ③ : 명령어를 자동으로 실행하기 위한 내용들이 설정되어 있다. (cat /root/.bashrc)
- ④ : 모든 사용자에게 적용되는 전역 변수 내용들이 설정되어 있다. (cat /etc/bashrc)
①④ : 전역 변수
②③ : 지역 변수
2) 계정 로그아웃할 때 다음과 같은 순서대로 해당 파일이 실행된다.
$HOME/.bash_logout -> $HOME/.bash_history
① ②
- ① : 로그아웃할때 실행되는 파일이며, 로그아웃 관련 배너 설정을 할 수 있다. (cat /root/.bash_logout)
- ② : 로그인 중에 실행했던 명령어들을 로그아웃할때 저장하는 파일이다. (cat /root/.bash_history)
Ex1) 쉘 관련 사용자 환경 파일 실행 순서 확인
[root@Client1 /root]# vi /etc/profile
echo "|---> /etc/profile read"
:wq
[root@Client1 /root]# vi /etc/profile.d/test.sh
#!/bin/bash
echo "|---> /etc/profile.d/*.sh read"
:wq
[root@Client1 /root]# vi .bash_profile
echo "|---> ~/.bash_profile read"
:wq
[root@Client1 /root]# vi .bashrc
echo "|---> ~/.bashrc read"
:wq
[root@Client1 /root]# vi /etc/bashrc
echo "|---> /etc/bashrc read"
:wq
[root@Client1 /root]# vi .bash_logout
echo "|---> ~/.bash_logout read"
:wq
[root@Client1 /root]# ssh localhost
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:gQyEDJzQ+MfBS35oKwqpv4GAOX0iwXGvImQ9cpd6vd0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
root@localhost's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Sat Mar 26 11:48:02 2022 from 192.168.2.1
|---> /etc/profile read
|---> /etc/profile.d/*.sh read
|---> /etc/bashrc read
|---> ~/.bash_profile read
|---> ~/.bashrc read
|---> /etc/bashrc read
[root@Client1 /root]# bash
|---> ~/.bashrc read
|---> /etc/bashrc read
|---> /etc/profile.d/*.sh read
[root@Client1 /root]# exit
exit
[root@Client1 /root]# exit
logout
|---> ~/.bash_logout read
Connection to localhost closed.
Ex2) user1으로 접속하여 실행된 파일 내용 및 순서 확인
[root@Client1 /root]# ssh user1@localhost
user1@localhost's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Sat Mar 26 11:33:49 2022 from 192.168.2.1
|---> /etc/profile read
|---> /etc/profile.d/*.sh read
|---> /etc/bashrc read
|---> /etc/bashrc read
[user1@Client1 /home/user1]$ bash
|---> /etc/bashrc read
|---> /etc/profile.d/*.sh read
[user1@Client1 /home/user1]$ exit
logout
[user1@Client1 /home/user1]$ exit
logout
Connection to localhost closed.
[root@Client1 /root]#
[참고] '.bash_history' 파일과 'history' 명령어 차이점
- '.bash_history' 파일에는 로그인 중에 실행했던 명령어들을 로그아웃할때 저장하는 파일이다.
- 'history' 명령어는 예전부터 로그인 중까지 실행했던 모든 명령어들을 확인할 수 있다.
[root@Client1 /root]# cat .bash_history
[root@Client1 /root]# history
- 사용자가 로그인 하게 되면 사용자의 명령어를 저장하기 위해서 'history'를 위한 Stack 공간이 할당된다.
- 이때, Bash 쉘은 기본 1000개 명령어까지 저장할 수 있으며, sh 쉘은 history 기능을 지원하지 않는다.
- 다음 명령어를 실행하면 history 정보는 삭제되지만, 다시 로그인하면 '.bash_history' 파일에 의해서 복구된ㄴ다.
[root@Client1 /root]# history -c
[root@Client1 /root]# history
5 history
- 다음 내용을 알아보기 위해서 쉘 관련 사용자 환경 파일 설정 내용을 삭제한다.
[root@Client1 /root]# vi /etc/profile
1 echo "|---> /etc/profile read" <- 삭제
2 # /etc/profile
:wq
[root@Client1 /root]# rm -rf /etc/profile.d/test.sh
[root@Client1 /root]# vi .bash_profile
1 echo "|---> ~/.bash_profile read" <- 삭제
2 # .bash_profile
:wq
[root@Client1 /root]# vi .bashrc
1 echo "|---> ~/.bashrc read" <- 삭제
2 # .bashrc
:wq
[root@Client1 /root]# vi /etc/bashrc
1 echo "|---> /etc/bashrc read" <- 삭제
2 # /etc/bashrc
:wq
[root@Client1 /root]# vi .bash_logout
1 echo "|---> ~/.bash_logout read" <- 삭제
2 # ~/.bash_logout
:wq
[참고] $HOME/.bashrc 재실행
- '$HOME/.bashrc' 파일 내용이 수정되고 적용되려면 쉘이 재실행되어야 한다.
- 그렇기 때문에 로그아웃 한 이후에 다시 로그인하면 쉘이 실행되기 때문에 새로 변경된 '.bashrc' 내용이 실행된다.
- 아니면 '. .bashrc', 'source .bashrc', 'source ~/.bashrc' 명령어를 이용하여 재실행해도 된다.
- 이때, 점(.)은 'source' 명령어와 같은 기능을 수행하지만, 권장하지는 않는다.
- 즉, 스크립트 파일을 실행하려면 점(.), source, sh, bash 명령어를 사용하면 된다.
[참고] 'source'와 'bash' 스크립트 파일 실행 차이점
용도 사용 쉘 환경 변수 유효성 'cd'로 명령어에 대한 경로 유지
source 스크립트 파일 실행 현재 쉘 파일 밖에서 접근 가능 파일 밖에서 유지 가능
bash 스크립트 파일 실행 새로운 쉘 파일 밖에서 접근 불가능 파일 밖에서 유지 불가능
[참고] 스크립트 파일 실행하는 방법
[root@Client1 /root]# rm -rf test
[root@Client1 /root]# mkdir test
[root@Client1 /root]# cd test
[root@Client1 /root/test]# cat << EOF > ping.sh
#!/bin/bash // 스크립트 파일을 만들때 필요하다.
echo "Ping Test Shell Script"
ping -c 1 168.126.63.1
EOF
[root@Client1 /root/test]# file ping.sh
ping.sh: Bourne-Again shell script, ASCII text executable
[root@Client1 /root/test]# ls -l ping.sh
-rw-r--r--. 1 root root 66 2022-05-30 10:41 ping.sh
Ex1) 'ping.sh' 스크립트 파일을 실행하기 위한 방법으로 틀린것은?
① sh ping.sh
② bash ping.sh
③ source ping.sh
④ . ping.sh
⑤ ./ping.sh
Ex2) 다음과 같은 방법으로 실행하려면 어떻게 해야하는가?
[root@Client1 /root/test]# ls -l ping.sh
-rw-r--r--. 1 root root 66 2022-05-30 10:41 ping.sh
[root@Client1 /root/test]# ./ping.sh
-bash: ./ping.sh: 허가 거부
4. 쉘 변수
- 변수는 파일로 동작하는 것이 아니라, 메모리에서 처리되며 동작한다.
- 그렇기 때문에 재부팅되거나 로그아웃 이후 로그인하면 변수 내용을 사라진다.
지역변수(Local Variable) : # VAR=5
환경변수(Environment Variable) : # export VAR=5
특수변수(Special Variable) : $$, $?, $!, $0, $1, $#, $*.........
1) 사용자 정의 변수
- 사용자가 임의로 만들어서 사용하는 변수이며, 로그아웃 또는 재부팅되면 내용은 사라진다.
- 만약, 로그인 중에 수동으로 삭제할 경우에는 unset 명령어를 사용한다.
[root@Client1 /root/test]# cd
[root@Client1 /root]# a=100
[root@Client1 /root]# b=200
[root@Client1 /root]# c=hello
[root@Client1 /root]# d="hello linux"
[root@Client1 /root]#
[root@Client1 /root]# echo $a
100
[root@Client1 /root]# echo $a $b $c $d
100 200 hello hello linux
[root@Client1 /root]# unset a b c d
[root@Client1 /root]# echo $a $b $c $d
[root@Client1 /root]# cat /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=ens33
UUID=5eefd56d-3a99-4156-b670-65a9e8532965
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.2.201
PREFIX=24
GATEWAY=192.168.2.254
DNS1=168.126.63.1
- 'NIC'라는 이름으로 네트워크 장치 파일 변수 설정
[root@Client1 /root]# NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# echo $NIC
/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# cat $NIC
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=ens33
UUID=5eefd56d-3a99-4156-b670-65a9e8532965
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.2.201
PREFIX=24
GATEWAY=192.168.2.254
DNS1=168.126.63.1
- NIC 변수는 'set' 명령어로 확인은 가능하지만, 환경 변수로 등록을 하지 않았기 때문에 'env' 명령어로를 검색되지 않는다.
[root@Client1 /root]# set | grep NIC
NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# env | grep NIC
- 'bash'를 하나 더 실행하여 'NIC' 변수 내용을 확인한다.
[root@Client1 /root]# bash
[root@Client1 /root]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 4012 4011 0 10:09 pts/0 00:00:00 -bash
root 6020 4012 0 11:34 pts/0 00:00:00 bash
root 6048 6020 0 11:34 pts/0 00:00:00 ps -f
[root@Client1 /root]# echo $NIC
[root@Client1 /root]# set | grep NIC
[root@Client1 /root]# env | grep NIC
[root@Client1 /root]# exit
exit
- 재접속 이후 'NIC' 변수 내용 확인
[root@Client1 /root]# exit
logout
[root@Client1 /root]# echo $NIC
[root@Client1 /root]# set | grep NIC
[root@Client1 /root]# env | grep NIC
2) 환경 변수
- 자주 사용하는 사용자 정의 변수를 환경 변수에 저장하면, 다음 로그인 및 재부팅할때도 사용이 가능하다.
- 그렇기 때문에 환경 변수를 '.bash_profile'에 설정하면 다음 로그인 및 재부팅할때 사용할 수 있다.
- 변수 이름은 대문자를 사용하는 것을 권장하며, 'env' 명령어를 이용하여 확인할 수 있다.
[root@Client1 /root]# env
~ 중간 생략 ~
SSH_CONNECTION=192.168.2.1 63247 192.168.2.201 22
LANG=ko_KR.UTF-8
HISTCONTROL=ignoredups
HOSTNAME=Client1
which_declare=declare -f
XDG_SESSION_ID=18
USER=root
SELINUX_ROLE_REQUESTED=
PWD=/root
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
HOME=/root
SSH_CLIENT=192.168.2.1 63247 22
SELINUX_LEVEL_REQUESTED=
XDG_DATA_DIRS=/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
SSH_TTY=/dev/pts/0
MAIL=/var/spool/mail/root
TERM=linux
SHELL=/bin/bash
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
LOGNAME=root
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
XDG_RUNTIME_DIR=/run/user/0
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PS1=[\u@\h $PWD]#
HISTSIZE=1000
LESSOPEN=||/usr/bin/lesspipe.sh %s
BASH_FUNC_which%%=() { ( alias;
eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}
_=/usr/bin/env
[root@Client1 /root]# env | grep HOSTNAME
HOSTNAME=Client1
[root@Client1 /root]# env | grep USER
USER=root
[root@Client1 /root]# env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@Client1 /root]# env | grep HOME
HOME=/root
[root@Client1 /root]# echo $HOSTNAME
Client1
[root@Client1 /root]# echo $USER
root
[root@Client1 /root]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@Client1 /root]# echo $HOME
/root
3) 변수 관련 명령어
- env : 전역 변수 설정 및 확인하는 명령어(# env 변수명=변수값)
- set : 사용자 환경 변수 설정 및 확인하는 명령어(# set 변수명=변수값)
- export : 쉘 변수를 환경 변수로 변경(등록)해주는 명령어(# export 변수명)
Ex) PS1, PS2 환경 변수 확인
- 현재 실습 환경에서 PS1 환경 변수는 전역 변수로 설정(등록)되어 있기 때문에 'env' 명령어로 확인이 가능하다.
[root@Client1 /root]# cat .bashrc | tail -4
alias vi='vim'
alias ls='ls --color=auto --time-style=long-iso'
PS1="[\u@\h \$PWD]# "
export PS1
[root@Client1 /root]# env | grep PS1
PS1=[\u@\h $PWD]#
[root@Client1 /root]# echo $PS1
[\u@\h $PWD]#
- PS2 환경 변수는 사용자 환경 변수로 설정되어 있기 때문에 'set' 명령어만로 확인할 수 있다.
[root@Client1 /root]# env | grep PS2
[root@Client1 /root]# set | grep PS2
PS2='> '
[root@Client1 /root]# echo $PS2
>
[참고] PS2 환경 변수
- 명령어가 아직 끝나지 않았음을 나타낼 때 사용하는 프롬프트를 정의하는 변수이다.
[root@Client1 /root]# ls -a \
> -l
합계 4
drwxr-xr-x. 2 root root 6 2022-03-26 11:30 .
dr-xr-x---. 17 root root 4096 2022-03-26 11:43 ..
4) 사용자 정의 변수를 환경 변수에 저장하는 방법
- 'export' 명령어를 사용하면 환경 변수를 저장한다.
[root@Client1 /root]# NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# set | grep NIC
NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# env | grep NIC
[root@Client1 /root]# export NIC
[root@Client1 /root]# env | grep NIC
NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# echo $NIC
/etc/sysconfig/network-scripts/ifcfg-ens33
- 'bash'를 하나 더 실행하여 'NIC' 변수 내용을 확인한다.
[root@Client1 /root]# bash
[root@Client1 /root]# ps -f
UID PID PPID C STIME TTY TIME CMD
root 6074 6073 0 11:35 pts/0 00:00:00 -bash
root 6236 6074 0 11:42 pts/0 00:00:00 bash
root 6266 6236 0 11:42 pts/0 00:00:00 ps -f
[root@Client1 /root]# env | grep NIC
NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# echo $NIC
/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# cat $NIC | tail -4
IPADDR=192.168.2.201
PREFIX=24
GATEWAY=192.168.2.254
DNS1=168.126.63.1
[root@Client1 /root]# exit
exit
- 재접속 이후 'NIC' 변수 내용 확인
[root@Client1 /root]# exit
logout
[root@Client1 /root]# set | grep NIC
[root@Client1 /root]# env | grep NIC
[root@Client1 /root]#
[root@Client1 /root]# echo $NIC
- 환경 변수에 NIC 변수를 계속 적용하는 방법
[root@Client1 /root]# vi .bash_profile // '.bashrc' 파일에 설정해도 무관함
14 NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
15 export NIC
:wq
- 재접속 이후 'NIC' 변수 내용 확인
[root@Client1 /root]# exit
logout
[root@Client1 /root]# env | grep NIC
NIC=/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# echo $NIC
/etc/sysconfig/network-scripts/ifcfg-ens33
[root@Client1 /root]# cat $NIC | tail -4
IPADDR=192.168.2.201
PREFIX=24
GATEWAY=192.168.2.254
DNS1=168.126.63.1
[참고] $HOME/.bash_profile 재실행
- $HOME/.bash_profile 파일 내용이 수정되고 적용되려면 쉘이 재실행되어야 한다.
- 그렇기 때문에 로그아웃 한 이후에 다시 로그인하면 쉘이 실행되기 때문에 새로 변경된 '.bash_profile' 내용이 실행된다.
- 아니면 '. .bash_profile', 'source .bash_profile', 'source ~/.bash_profile' 명령어를 이용하여 재실행해도 된다.
- 이때, 점(.)은 'source' 명령어와 같은 기능을 수행하지만, 권장하지는 않는다.
- 즉, 스크립트 파일을 실행하려면 점(.), source, sh, bash 명령어를 사용하면 된다.
Ex1) .bash_profile 예제
- AA 변수에 100, BB 변수에 200을 선언하고, 로그인될때 마다 적용되도록 구성한다.
- 구성이 완료되었다면, 로그아웃/로그인 진행 없이 바로 적용되도록 한다.
[root@Client1 /root]# env | egrep "AA|BB"
AA=100
BB=200
[root@Client1 /root]# echo $AA $BB
100 200
Ex2) .bashrc 예제
- .bashrc 파일에 alias pg='ps -ef | grep $1' 를 추가한다.
- 추가가 완료되었다면, 로그아웃/로그인 진행 없이 'pg sleep' 명령어가 가능하도록한다.
[root@Client1 /root]# pg sleep
root 6519 952 0 11:51 ? 00:00:00 sleep 60
root 6555 6381 0 11:52 pts/0 00:00:00 grep --color=auto sleep