[쉘프로그래밍] 리눅스 부팅과정, 기본적인 명령어
P.182
- 2장. 리눅스 부팅과정
POST -> Boot Loader (GRUB) -> Linux Kernel Loading -> init 프로세스 생성
(1) POST (Power-On Self Test) : 전원 공급하면 가장 처음에 자가 진단프로그램 포스트가 돈다(ex. IBM컴퓨터의 경우 bios 라고 함)
(2) 부딩디스크의 가장 첫번째 섹션에 boot loader가 있다. 부트로더는 운영체제의 커널을 불러온다. 리눅스에서 사용하는 부트로더는 GRUB (GNU프로젝트의 부트로더) 이다.
(3) 해당하는 커널을 찾아 메모리에 올린다.
(4) 커널은 제일 먼저 init이라는 프로세스를 생성하여 실행한다.
그러면 init프로세스가 어떤 동작을 실행해야하는지 정의하는 곳은 어디있을까?
/etc/inittab 이다. inittab안에는 런 레벨(Run level)에 따라 실행될 쉘스크립트 파일을 지정해놓고 있다.
다음과 같은 파일들로 지정된다. 아래 rc0~6.d 파일명에서 숫자는 런 레벨을 의미한다.
/etc/rc.d/rc.sysinit
/etc/rc.d/rc0.d
/etc/rc.d/rc1.d
/etc/rc.d/rc2.d
/etc/rc.d/rc3.d
/etc/rc.d/rc4.d
/etc/rc.d/rc5.d
/etc/rc.d/rc6.d
Run Level
0 : system halt (시스템을 종료할때 사용되는 런레벨)
1 : single-user (maintenance) 싱글 유저 모드. 런레벨 1로 시작하면 디폴트로 root 로 로그인한다. 다른사용자 로그인 시도 못하고 오직 관리자만 진입하여 작업하는 용도로 사용된다.
2 : multi-user
3 : multi-user, NFS(Network File System : 로컬 머신이 아닌 다른 머신의 하드를 자신의 머신에 있는 것처럼 네트워크를 이용하여 만드는 가상파일시스템) 를 지원한다.
=> 서버용으로 구동하려면 2번 또는 3번으로 구동해야한다.
5 : 리눅스에서 Desktop 형태(그래픽환경, 현재 실습하고있는 부팅레벨)
6 : 리눅스에서 reboot
=> 5,6 번은 리눅스와 유닉스가 다른 용도로 사용할수있음, 0~3까지는 리눅스든 유닉스든 공통적인 용도로 사용됨
현재 몇 레벨을 사용하는지 알아보는 방법은?
[user@localhost rc.d]$ who -r
run-level 5 2017-06-20 09:54
결과에 5라고 나온다. 즉 5번(데스크탑 모드) 런레벨로 부팅되었다는 뜻
/etc/rc.d/rc#.d 의 하위폴더 들어가보면 하위 파일들이 나온다. K로 시작하는 것과 S로 시작하는 쉘 파일들이 있다.
K~~~ 인 것 : 종료시키는 스크립트
S~~~ 인 것 : 시작시키는 스크립트
[user@localhost rc5.d]$ pwd
/etc/rc.d/rc5.d
[user@localhost rc5.d]$ ls -al *crond
lrwxrwxrwx. 1 root root 15 2016-05-20 06:41 S90crond -> ../init.d/crond
S로 시작하는 것으로보아 시작과 관련된 쉘프로그램이고 심볼릭링크로 연결되어 있음을 알 수 있다.
p185.
p194. 명령어 라인 분석 순서
p195.
p198. pstree , 부모자식관계
p199. system call - 커널안에
-내부에서 시스템콜 호출하면 - fork가 수행된다. 이때 어떻게 동작할까?
프로세스의 내부구조는 Segment(실행하는 코드 정보가 있음), F.D.T(Fire Despriptor Table) 크게 두개 이외에도 Signal Handler, Process정보가 저장되는 영역 (PID,state 정보 등) 등으로 구성된다.
프로세스가 외부자원을 사용할때는 <File Descriptor Table> 을 사용한다.
File Descriptor Table에 외부자원과 참조번호를 연결해두고 사용한다.
* 외부자원 : 터미널(키보드입력, 모니터출력 등), 하드디스크, 네트웍, 소켓 등
fork를 사용하면 나와 똑같은 프로세스가 하나 더 복제된다. (복제시 세그먼트, FDT, signal 핸들러 등의 정보는 나와 똑같은 정보가 복사된다.)
그러나 pid, ppid, state 같이 프로세스 정보가 저장되는 영역은 복제되지 않는다. 자식 쉘도 자기만의 정보가 저장되어 있다.
이때 나는 parent 프로세스 , 새로생긴애는 child 프로세스라고 한다. 새로생긴애의 ppid 정보에 내 프로세스 pid 값이 저장된다.
생성된 child 프로세스는 부모와 똑같은 세그먼트를 갖게 되나, 세그먼트 내에서 fork 이후의 로직부터 수행한다. (segment의 처음부분 부터 수행하는게 아니다)
exec와 물음표변수 $? 는 밀접하게 관련있다.
exec 결과를 $? 로 확인해야하기 때문이다.
p208 변수
변수 값할당시 =사이에 공백있으면 안됨 즉,
$name=kim (o)
$name = kim (x)
명령어 줄에서 변수 지정한 후, 쉘 스크립트 파일 (~.sh) 안에서 사용하려고 하면 안된다. 왜 일까요?
명령프롬프트에서 변수 지정하는 것은 부모 쉘인 내가 지정한 것이고, 쉘 스크립트를 실행하면 자식 쉘이 생성되어 실행하는 것이기 때문
(부모 쉘에서 지정한 변수가 자식 쉘에게 자동으로 변수 전달 안됨)
부모쉘과 자식쉘의 환경(변수 포함)이 다르기 때문
만약, 자식쉘에도 이 정보를 전달하고 싶은 경우 export 명령어를 쓰면 된다. export란 전역화 시킨다는 의미이다.
$export name
위 명령어를 쓰고나면 env 명령어로 검색하면 다음과 같이 name 변수를 전역변수에서 찾을 수 있다.
$env 했을때
...(중략)
name=kim
..(중략)
변수를 해제하고 싶을땐? unset 명령어를 쓰면 변수의 메모리할당을 제거함
$unset name
$echo $MAIL
메일이라는 환경변수
- 프롬프트 관련 환경변수
$PS1 | 프롬프트 |
$PS2 | secondary 프롬프트 (명령어를 미처 완성하지 못했을때 완성할때까지 뜨는 프롬프트) |
$PS3 | select 라는 명령어를 쓸때 나오는 프롬프트이다 (select는 나중에 살펴보겠다) |
[test@localhost ~]$ echo $PS1
[\u@\h \W]\$
[test@localhost ~]$ echo $PS2
>
[test@localhost ~]$ echo $PS3
p224. 예약변수
[user@localhost ch02]$ env | grep HIST
HISTSIZE=1000 (최근 수행 명령어 저장 개수, 기본값은 1000이다.)
HISTCONTROL=ignoredups (중복되어지는 명령에 대한 기록 유무 지정)
명령어 기록기능
~/.bash_history 파일에 저장됨
터미널 로그아웃시 .bash_history 에 명령어 히스토리를 저장함
[user@localhost ch02]$ cat ~/.bash_history
cd
ls
cd ~
ls
alias c=clear
c
(중략)
p226. 특수파라메터 변수들 (중요하다)
$* : 인수 총 목록
$@ : 인수 총 목록
$# : 인수의 개수
$0 : 0번째 인수, 쉘스크립트 파일명
$1 : 1번째 인수,
$2 : 2번째 인수
$N : N번째 인수
[user@localhost ch02]$ ./crond start load위와 같은 명령어를 사용했을때
$0 : ./crond
$1 : start
$2 : load
$# : 2
$* : start load
$@ : start load
예)
쉘스크립트------------------------------------
[user@localhost ch02]$ cat tmp.sh
#!/bin/bash
# positional parameter var
echo "\$0 : $0" <---역슬래시(\)를 넣으면 특수문자를 일반 문자로 처리한다
echo "\$1 : $1"
echo "\$2 : $2"
echo
echo "\$# : $#"
echo "\$* : $*"
echo "\$@ : $@"
결과1------------------------------------
[user@localhost ch02]$ ./tmp.sh ha hoo yoon
$0 : ./tmp.sh
$1 : ha
$2 : hoo
$# : 3
$* : ha hoo yoon
$@ : ha hoo yoon
결과2------------------------------------
[user@localhost ch02]$ ./tmp.sh RED BLUE GREEN BLACK
$0 : ./tmp.sh
$1 : RED
$2 : BLUE
$# : 4
$* : RED BLUE GREEN BLACK
$@ : RED BLUE GREEN BLACK
결과3------------------------------------
[user@localhost ch02]$ ./tmp.sh
$0 : ./tmp.sh
$1 :
$2 :
$# : 0
$* :
$@ :
$? 변수는 별다섯개임
정상종료시 0, 비정상종료시 0이 아닌 값을 의미한다
- 실행중인 pid 값을 확인하는 법은 $$ 사용.
이 변수는 주로 쉘 프로그램 안에서 임시파일을 만들고, 그 파일의 삭제작업까지 원할때 많이 사용
echo $$
- 가장최근에 실행한 pid
$!
- read 커맨드. 사용자의 입력을 원할때 사용
$read 저장될변수명
쉘스크립트------------------------
[user@localhost ch02]$ cat read.sh
#!/bin/bash
echo "what is your name?"
read myname
echo "My name is $myname"
결과화면 ------------------------
[user@localhost ch02]$ ./read.sh
what is your name?
hyojin
My name is hyojin
p234 산술계산
- expr 명령어
각 인자 사이 정확히 공백을 띄워야 한다.
-let 명령어
변수에 산술식을 지정할 수 있다. let이 expr보다는 좀 더 사용하기 쉽다.
[user@localhost ch02]$ expr 10 + 20
30
[user@localhost ch02]$ let num=10+20 <--let을 쓸때는 변수에 지정하므로 = 사이에 공백 없는 것을 확인할 수 있다.
[user@localhost ch02]$ echo $num
30
[user@localhost ch02]$ let num=num+1
[user@localhost ch02]$ echo $num
31
[user@localhost ch02]$ num1=`expr 10 + 20`
[user@localhost ch02]$ echo $num1
30
[user@localhost ch02]$ num1=`expr $num1 + 1`
[user@localhost ch02]$ echo $num1
31
p234 연산자
문자열의 동등관계 확인은?
test 명령어, 혹은 대괄호로 논리연산 할 수 있다.
연산자 | 의미 |
= | 같은가 |
!= | 다른가 |
|
|
test 명령어 사용 방법
[user@localhost ch02]$ test "kim" = "lee" <--- 반드시 연산자 "=" 양쪽 사이로 공백을 띄워야 한다.
[user@localhost ch02]$ echo $?
1 (거짓이라는 의미)
[user@localhost ch02]$ test "kim" != "lee"
[user@localhost ch02]$ echo $?
0 (참이라는 의미)
test 명령어 대신 대괄호를 써도 된다. 한칸 띄고 [ 내용 ]
[user@localhost ch02]$ [ "kim" = "lee" ] <--- 반드시 연산자 "=" 양쪽 사이로 공백을 띄워야 한다.
[user@localhost ch02]$ echo $?
1
[user@localhost ch02]$ [ "kim" != "lee" ]
[user@localhost ch02]$ echo $?
0
문자열로 저장된 변수를 숫자 대수비교하고 싶을때는 아래 비교 명령어를 쓴다. 그러나 문자를 비교는 불가하므로 문자비교시에는 "=", "!=" 이거만 써야한다
-gt ( greater than, 앞에꺼가 뒤에꺼보다 클때)
-ge ( 앞에꺼가 뒤에꺼보다 크거나, 같을때)
-lt ( less than, 앞에꺼가 뒤에꺼보다 작을때 )
-le (앞에꺼가 뒤에꺼보다 작거나, 같을때)
-eq (같을때)
-ne (같지 않을때)
[user@localhost ch02]$ num1=10
[user@localhost ch02]$ num2=20
[user@localhost ch02]$ [ $num1 -eq $num2 ]
[user@localhost ch02]$ echo $?
1 (두 값이 다르다)
[user@localhost ch02]$ [ $num1 -gt $num2 ]
[user@localhost ch02]$ echo $?
1 (거짓이다)
[user@localhost ch02]$ [ $num1 -lt $num2 ]
[user@localhost ch02]$ echo $?
0 (참이다)
not연산 (! 느낌표 주고 반드시 공백띄워야함)
[user@localhost ch02]$ [ ! $num1 -lt $num2 ]
[user@localhost ch02]$ echo $?
1
p239 test명령어 또는 대괄호를 이용하면 파일에 대한것도 체크할수있다
-z 옵션 : 변수에 값이 없으면 참,
-f 옵션 : 일반 파일인지 체크
-d 옵션 : 디렉토리인지 체크
-r 옵션 : 읽기권한있나
-w 옵션 : 쓰기권한있나
-x 옵션 : 실행권한있나
위 옵션 사용시 유의해야 할 사항! 옵션 다음에 나오는 변수는 무조껀 이중따옴표로 묶어야 한다. 왜?
시스템이 명령어를 실행하는 순서에서 치환기법을 사용하는데, 명령어에서 $변수를 값으로 치환하는 작업이 먼저 일어나므로 $변수에 값이 없다면
[ -f $변수 ] 라고 작성했을지라도 치환 작업에 의해 [ -f ] 로 변해버려서 에러가 나기때문이다. 그러므로 꼭
[ -f "$변수" ] 로 사용해라.
- 반드시 대괄호 직후&직전 한칸띄기, 안에 변수넣을때 쌍따옴표로 묶기
[user@localhost ch02]$ [ -f /etc/hosts ] <-- 일반 파일인가?
[user@localhost ch02]$ echo $?
0 (일반파일입니다)
[user@localhost ch02]$ [ -d /etc/hosts ] <-- 디렉토리인가?
[user@localhost ch02]$ echo $?
1 (디렉토리아닙니다)
[user@localhost ch02]$ [ -r /etc/hosts ] <-- read 권한이 있는가?
[user@localhost ch02]$ echo $?
0
[user@localhost ch02]$ [ -w /etc/hosts ] <-- write 권한이 있는가?
[user@localhost ch02]$ echo $?
1
[user@localhost ch02]$ [ -x /etc/hosts ] <-- 실행 권한이 있는가?
[user@localhost ch02]$ echo $?
1
Q. 그런데 파일퍼미션이 rwxrwxrwx 총 3개의 권한을 표시하는데, 그중 어떤 권한을 보고 위를 판단하는건지 모르겠다 ?
스크립트--------------------------------------------[user@localhost ch02]$ cat test.sh
#!/bin/bash
# . ./filecheck.sh file_name
[ -z "$1" ] && exit 1 <---- 부모에게 1이라고 신호전달
[ -f "$1" ] && echo "this is regular file" <-- 반드시 대괄호 직후,직전 한칸띄기, 안에 변수넣을때 쌍따옴표로 묶기
[ -d "$1" ] && echo "this is directory"
[ -x "$1" ] && echo "possible to execute"
[ -w "$1" ] && echo "writable"
[ -r "$1" ] && echo "readable"
실행결과 ---------------------------------------------------
[user@localhost ch02]$ ./test.sh /etc/hosts
this is regular file
readable
실행결과 ---------------------------------------------------
[user@localhost ch02]$ ./test.sh
[user@localhost ch02]$ echo $?
1 <---자식이 exit 1로 전달한 값 확인 "아 비정상종료했구나"
실행결과 ---------------------------------------------------
[user@localhost ch02]$ ls -al ~/ls.out
-rw-rw-r--. 1 user user 33 2017-06-20 15:40 /home/user/ls.out
[user@localhost ch02]$ ./test.sh ~/ls.out
this is regular file
writable
readable
p235. if 조건문
if 조건 then 수행 else fi | 조건을 한줄에 쓸려면 세미콜론 이용 if 조건 ; 수행 | if then elif then else fi |
스크립트 ----------------------------------------------
[user@localhost ch02]$ cat ifcheck.sh
#!/bin/bash
# . ./ifcheck.sh file_name
if [ -z "$1" ]
then
exit 1
fi
if [ -f "$1" ]
then
echo "this is regular file"
elif [ -d "$1" ]
then
echo "this is directory"
else
echo "unrecognized file"
fi
if [ -x "$1" ]
then
echo "possible to execute"
elif [ -w "$1" ]
then
echo "writable"
elif [ -r "$1" ]
then
echo "readable"
fi
실행결과 ----------------------------------------------
[user@localhost ch02]$ ./ifcheck.sh /etc/hosts
this is regular file
readable
실행결과 ----------------------------------------------
[user@localhost ch02]$ ./ifcheck.sh /var/log
this is directory
possible to execute
실행결과 ----------------------------------------------
[user@localhost ch02]$ ./ifcheck.sh /var/log
this is directory
possible to execute
실행결과 ----------------------------------------------
[user@localhost ch02]$ ./ifcheck.sh /var/log/messages
this is regular file
실행결과 ----------------------------------------------
[user@localhost ch02]$ ls -l /var/log/messages
-rw-------. 1 root root 360866 2017-06-21 11:41 /var/log/messages
centOS에 한글패키지( ibus-hangul) 설치하는 방법 (관리자 모드로 입장)
[root@localhost ~]# yum install ibus-hangul
언제 공백을 넣는지 반드시 체크해야함
명령과 옵션사이 반드시 공백
대괄호[ 앞뒤 공백 ] 이것도 앞뒤공백
* 이 사용자가 등록된 사용자인지 아닌지 확인은 어디서 할까?? -------------------- /etc/passwd 에서 유저를 찾으면 된다.
[user@localhost ch02]$ cat useradd.sh
#!/bin/bash
# 사용자 계정이 존재하지 않는 경우 생성
echo "User name?"
read username
grep $username /etc/passwd >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "${username}은 이미 존재합니다"
else
useradd $username
passwd $username
fi
- case
case 표현식 in 문자열1) ;; 문자열2) ;; *) ;; 문자열3|문자열4) ;; esac |
예)
[user@localhost ch02]$ cat case.sh
#!/bin/bash
echo "1. loginuser list"
echo "2. file list"
echo "3. process list"
echo "4. all prosess list"
echo "choice ==> "
read answer
case $answer in
1)
who
;;
2)
ls
;;
3|4)
ps
;;
"start")
who
;;
*)
;;
esac
-반복문
(1) while 명령어 do 수행내용 done 명령어가 참이면 수행내용수행 | (2) until 명령어 do 수행내용 done 명령어가 거짓이면 수행내용수행 | (3) for 변수 in 값... #for 변수 in `명령어` #for 변수 in $* (사용자가 입력하는 인수 목록을 넣을수도 있다) do 수행내용 done |
스크립트 ------------------------------------
[user@localhost ch02]$ cat for.sh
#!/bin/bash
for i in 1 2 3 4 5
do
echo "$i"
done
실행결과 ------------------------------------
[user@localhost ch02]$ ./for.sh
1
2
3
4
5
--스크립트 --[user@localhost ch02]$ cat for.sh
#!/bin/bash
for i in `ls /etc/*.conf`
do
echo "$i"
done
--실행결과 --
[user@localhost ch02]$ ./for.sh
/etc/asound.conf
/etc/dnsmasq.conf
/etc/dracut.conf (중략)
--스크립트 --
[user@localhost ch02]$ cat for.sh
#!/bin/bash
for i in $*
do
echo "$i"
done
--실행결과 --
[user@localhost ch02]$ ./for.sh aa ho joo
aa
ho
joo
--스크립트 --
[user@localhost ch02]$ cat mkdir.sh
#!/bin/bash
for dirname in 00 01 02 03 04 05 06 07 08 09
do
mkdir unix$dirname
cd unix$dirname
touch file1 file2 file3
cd ..
done
--실행결과 --
[user@localhost ch02]$ ls -R unix*
unix00:
file1 file2 file3
unix01:
file1 file2 file3
unix02:
file1 file2 file3
unix03:
file1 file2 file3
unix04:
file1 file2 file3
unix05:
file1 file2 file3
unix06:
file1 file2 file3
unix07:
file1 file2 file3
unix08:
file1 file2 file3
unix09:
file1 file2 file3
p243 함수
함수 : 함수정의 먼저 하고 실행해야한다. 순서가 뒤바뀌면 안된다!!! (중요)
(1) 함수명() { 내용 } | (2) function 함수명 { 내용 } |
--스크립트--
[user@localhost ch02]$ cat myfunc.sh
#!/bin/bash
#함수정의
myprint()
{
echo "myprint"
}
#함수호출
myprint
pwd
cd /etc
myprint
pwd
--실행결과 --
[user@localhost ch02]$ ./myfunc.sh
myprint
/home/user/shell/ch02
myprint
/etc
-함수에 인수전달방법
함수정의는 다음과 같이
함수명()
{
$1 <-첫번째 인자
}
함수호출은 다음과 같이
함수명 인자1 인자2
--스크립트 --
[user@localhost ch02]$ cat myfunc.sh
#!/bin/bash
#함수정의
myprint()
{
echo "myprint $1"
}
#함수호출
myprint var1
pwd
cd /etc
myprint var2
pwd
--실행결과--
[user@localhost ch02]$ ./myfunc.sh
myprint var1 <-- 인자넣음
/home/user/shell/ch02
myprint var2 <-- 인자 또넣음
/etc
외부파일 functions에 함수정의해놓고 불러다쓰기
---- 함수 정의해놓은 functions 스크립트 ---
[user@localhost ch02]$ cat functions
#!/bin/bash
#함수정의
myprint()
{
echo "myprint $1"
}
-----외부 파일에서 함수 불러다쓰는 스크립트
[user@localhost ch02]$ cat myfunc.sh
#!/bin/bash
#함수정의
. functions <-- 외부에 함수저장해놓은 functions파일을 적용시키는 명령어
#함수호출
myprint var1
pwd
cd /etc
myprint var2
pwd
[user@localhost ch02]$
---실행결과----
[user@localhost ch02]$ ./myfunc.sh
myprint var1
/home/user/shell/ch02
myprint var2
/etc
#!/bin/bashecho "filename?"read filenamebackupfile=${filename##*/}echo $backupfile <---파일명만 떼는법extfile=${backupfile##*.}echo $extfile <----확장자떼는법case $extfile in"gz")option=z;;"xz")option=J;;"bz2")option=j;;*)echo "잘못되었습니다"exit 1;;esaccd /tmptar xv${option}f $filename~"mytar.sh" 28L, 296C 저장 했습니다----[user@localhost ~]$ ./mytar.shfilename?/tmp/backup.tar.bz2backup.tar.bz2bz2home/user/shell/home/user/shell/ch01/home/user/shell/ch01/first.shhome/user/shell/ch01/20170619.txthome/user/shell/ch01/sample2.shhome/user/shell/ch01/sample.shhome/user/shell/ch02/home/user/shell/ch02/testhome/user/shell/ch02/mkdir.shhome/user/shell/ch02/sheellpid.shhome/user/shell/ch02/functionshome/user/shell/ch02/read.shhome/user/shell/ch02/test05.shhome/user/shell/ch02/testthome/user/shell/ch02/while.shhome/user/shell/ch02/ifcheck.shhome/user/shell/ch02/useradd.shhome/user/shell/ch02/for.shhome/user/shell/ch02/logincheck.shhome/user/shell/ch02/myfunc.shhome/user/shell/ch02/case.shhome/user/shell/ch02/ifself.shhome/user/shell/ch02/var.shhome/user/shell/ch02/filecheck.shhome/user/shell/ch02/hyojinhome/user/shell/ch02/tmp.sh----
------homecheck.sh ----------------#!/bin/bashif [ $# -eq 0 ]thendu -sh /home/*elsefor username in $@doif [ -d /home/$username ]thendu -sh /home/$usernameelseecho "wrong name"fidonefi
--스크립트
[user@localhost ~]$ cat logincheck.sh
#!/bin/bash
echo "사용자를 입력하세요"
read username
while [ 1 -eq 1 ]
do
who | grep $username >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "$username 로그인했습니다"
sleep 5
ps -ef | grep ^${username}
else
echo "$username 로그인하지 않았습니다"
sleep 5
who | grep $username >/dev/null 2>&1
fi
done
[user@localhost ~]$
--실행결과
[user@localhost ~]$ ./logincheck.sh
사용자를 입력하세요
test
test 로그인하지 않았습니다
test 로그인하지 않았습니다
test 로그인하지 않았습니다
test 로그인했습니다
test 34783 34773 0 11:08 ? 00:00:00 sshd: test@pts/2
test 34784 34783 0 11:08 pts/2 00:00:00 -bash
test 로그인했습니다
test 34783 34773 0 11:08 ? 00:00:00 sshd: test@pts/2
test 34784 34783 0 11:08 pts/2 00:00:00 -bash
test 34811 34784 0 11:09 pts/2 00:00:00 cat
test 로그인했습니다
test 34783 34773 0 11:08 ? 00:00:00 sshd: test@pts/2
test 34784 34783 0 11:08 pts/2 00:00:00 -bash
test 로그인했습니다
test 34783 34773 0 11:08 ? 00:00:00 sshd: test@pts/2
test 34784 34783 0 11:08 pts/2 00:00:00 -bash
test 로그인했습니다
^C
[user@localhost ~]$