'리눅스'에 해당되는 글 21건

  1. 2013.01.16 NFS daemon 수 수정
  2. 2012.12.28 core 파일 생성법
  3. 2012.12.28 커널 패닉 분석
  4. 2012.10.18 Bash 내부 명령어
  5. 2012.10.18 Bash 외부 명령어
  6. 2012.10.18 Redirection
  7. 2012.10.16 cpu 갯수 확인하기
  8. 2012.10.16 screen 명령어
  9. 2012.05.22 poll을 이용한 입출력 다중화
  10. 2012.03.30 리눅스에서 이전 폴더로 이동하기

http://h10025.www1.hp.com/ewfrf/wc/document?cc=kr&lc=ko&dlc=ko&docname=c02677990
suse linux에서 nfs daemon 수를 변경하는 방법입니다.
세부사항
  1. 현재 설정 값 및 실제 nfs deamon thread 갯수 확인 # cat /proc/fs/nfsd/threads # ps -ef |grep nfsd |wc -l
  2. nfsd daemno 수를 변경하는 방법 현재 설정 값 및 실제 nfs deamon thread 갯수 확인 # cat /proc/fs/nfsd/threads # ps -ef |grep nfsd |wc -l
    • realtime 변경 # echo 256 > /proc/fs/nfsd/threads # cat /proc/fs/nfsd/threads # ps -ef |grep nfsd |wc -l
    • manual 변경 # vi /etc/sysconfig/nfs USE_KERNEL_NFSD_NUMBER="4" <-- 값을 필요한 수로 변경 # service nfsserver restart <-- nfs만 재시작 또는 # shutdown -r now <-- System Restart # cat /proc/fs/nfsd/threads # ps -ef |grep nfsd |wc -l
    • nfsd daemon 사용량 점점 아래 data를 받아 엔지니어에게 분석요청하면 사용량을 알 수 있음. # cat /proc/net/rpc/nfsd



http://blog.naver.com/PostView.nhn?blogId=kimplove&logNo=130023298102&redirect=Dlog&widgetTypeCall=true

vi /etc/rc.d/init.d/nfs

 

파일안에

# Number of servers to be started by default

[ -z "$RPCNFSDCOUNT" ] && RPCNFSDCOUNT=16

 

숫자를 바꾸어준다.

 

그리고 nfs 리스타트한다.

 

 

 

* nfsd 수 조정

Ø vi /etc/rc.d/init.d/nfs  => RPCNFSDCOUNT=16
Ø 32 node cluster may be able to have 8 nfsd processes. However, if each node perfoems lots of NFS operations, 16 node cluster may well need 16 nfsd processes.
Ø netstat -s | grep overflow 마지막 이후 누적된 소켓 오버플로우수가 표시. 이 수가 크게 증가하고 NFS 클라이언트가 이 서버에서 반응을 제대로 얻지 못하면 nfsd를 더 증가시켜야한다.

[출처] nfsd 수 늘리기|작성자 기성

'리눅스 > 일반' 카테고리의 다른 글

NFS daemon 수 수정  (0) 2013.01.16
Bash 내부 명령어  (0) 2012.10.18
Bash 외부 명령어  (0) 2012.10.18
Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
Posted by 라판
TAG NFS

대개 응용의 crash가 날 경우, core파일을 통해 디버깅할 수 있는데, 

간혹 생성되지 않을 경우가 있다. 

 웬만한 것을 건들지 않는다는 가정하에 간단한 해결책은 

ulimit -a 로 core dump에 대한 size가 너무 적거나 0이 되어 있는지 확인하고 이를, 

ulimit -c unlimited로 해주는 것이 가장 속편하다. 


core는 프로그램의 비정상적인 종료(세그먼트 폴트 등)가 발생하는 경우
커널에서 해당 프로세스와 관련된 메모리를 덤프시킨 파일이다.

아래와 같이 리눅스는 기본적으로 코어덤프를 하지 않도록 되어있다.
# ulimit -aS 또는 ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
pending signals                 (-i) 1024
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 2048
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 2047
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited 


코어덤프를 하도록 설정하려면 위 부분에서
core file size          (blocks, -c) 0 이부분이 값(KB)나 unlimited로 되어있어야만 한다.

- core dump를 하도록 설정하는 방법
# ulimit -c unlimited
# ulimit -c 1048576 (KB) - 1G 제한을 두는 경우

- 간단하게 dump된 core 파일에서 문자열(string)만을 보려면
# strings core | more

- 자세한 debugging을 원할 경우에는 gdb라는 툴을 사용하면 된다.(gdb 맨페이지 참고)


예전에는 단순히 core가 dump될 때 단순히 core라는 이름으로 생성이 되었는데
이 경우 어떤 프로세스에서 core가 발생했는지 확인하는 문제가 있었다.
하지만 요 근래의 Red Hat Linux를 보면 core.PID로 생성이 된다.
core와 관련된 커널 파라미터 설정은 다음과 같다.

# sysctl -a | grep core
kernel.core_pattern = core
kernel.core_uses_pid = 1

# cat /proc/sys/kernel/core_pattern
core

# cat /proc/sys/kernel/core_uses_pid
1  (0일 경우 pid를 출력하지 않음)


- core 덤프가 발생할 때 프로세스 실행파일명으로 core 덤프를 떨어뜨리는 방법
1) sysctl -w kernel.core_pattern = core.%e  (reboot후 초기화 된다.)

2) echo "core.%e" > /proc/sys/kernel/core_pattern

3) /etc/sysctl.conf 파일에 아래 내용을 등록해 준다.
kernel.core_pattern = core.%e

- 강제로 특정 프로세스에 대한 core를 발생시키는 방법
디버깅을 위해 특정 프로세스에 대해 강제로 core dump를 발생시켜야 하는 경우
kill 커맨드를 이용할 수 있다.

# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     17) SIGCHLD
18) SIGCONT     19) SIGSTOP     20) SIGTSTP     21) SIGTTIN
22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO
30) SIGPWR      31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1
36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4  39) SIGRTMIN+5
40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8  43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6  59) SIGRTMAX-5
60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2  63) SIGRTMAX-1
64) SIGRTMAX

위의 시그널 중에서 8)SIGFPE 또는 3)SIGQUIT 를 통해 core를 dump시킬 수 있다.
# top (top 실행)
# ps -ef | grep -i top (top 프로세스 PID 확인, 다른 터미널에서)
root     31775 29667  0 14:30 pts/3    00:00:00 top

# kill -SIGFPE 31775

위와 같이 하면 top을 실행한 디렉토리에 core.top.31775가 생성되어있음을 확인할 수 있다.


- gcore를 이용한 core dump 발생
디버깅을 위해 현재 실행중인 프로세스를 강제로 core dump를 생성할 필요가 있는 경우 gcore를 이용할 수 있다.

# top (top 실행)
# ps -ef | grep -i top (top 프로세스 PID 확인, 다른 터미널에서)
root     31775 29667  0 14:30 pts/3    00:00:00 top

# gcore 31775
gcore: core.31775 dumped

참고 : gcore 바이너리는 gdb 패키지에 포함돼 있다. (gdb-6.3.0.0-1.143.el4.i386.rpm)


=========================================================================================================================================

[ 참고 자료]

아래는 각각의 OS 플랫폼에서 core 파일 정보를 확인하는 결과이다.
각각의 플랫폼에서는 다음과 같은 결과가 나왔다 :

$ uname -a;file core                                     
SunOS v880 5.8 Generic_117350-51 sun4u sparc SUNW,Sun-Fire-880
core:           ELF 32-bit MSB core file SPARC Version 1, from 'a.out'

$ uname -a; file core
AIX aix5 3 5 0001D01F4C00
core: AIX core file 32-bit, a.out

% uname -a; file core
HP-UX hp1123 B.11.23 U 9000/800 190494686 ??????-????? ???̼???
core:           core ???? - 'a.out' - SIGBUS ????

$ uname -a; file core.528 
Darwin castepo.local 9.3.0 Darwin Kernel Version 9.3.0: Fri May 23 00:49:16 PDT 2008; root:xnu-1228.5.18~1/RELEASE_I386 i386
core.528: Mach-O core i386
때때로 여러개의 프로세스를 마구 띄우는 daemon 을 작업하다 보면 뜬 프로세스들 중 하나가 죽을 경우에 생기는 core 파일이 도대체 어느 프로그램이 죽어서 생긴 것인지 알 수 없을 경우가 있다. 물론, 하나씩 디버거로 읽어서 뭔가 좀 말이 되는 콜스택을 보여준다든지 하는 녀석을 대충 지레짐작해서 얘이거니 하고 분석할 수도 있지만, 기분 나쁘다.

리눅스 맨페이지에 따르면 커널 버젼 2.6 이후, 그리고 2.4.21 이후의 커널에 다음의 기능이 추가되어 있다고 한다 :
$ man core | col -b 
.
.
.
   Naming of core dump files
       By default, a core dump file is    named  core,  but  the    /proc/sys/ker-
       nel/core_pattern file (since Linux 2.6 and 2.4.21) can be set to define
       a template that is used to name core dump files.  The template can con-
       tain  % specifiers which are substituted by the following values when a
       core file is created:

     %%  A single % character
     %p  PID of dumped process
     %u  real UID of dumped process
     %g  real GID of dumped process
     %s  number of signal causing dump
     %t  time of dump (seconds since 0:00h, 1 Jan 1970)
     %h  hostname (same as 'nodename' returned by uname(2))
     %e  executable filename


말인 즉슨, 다음과 같이 하면 core file 이 생성될 때 그 파일의 이름을 어떻게 지을 것인가 하는 문제를 사용자가 설정할 수 있다는 이야기인데, cut to the chase, 결론부터 말하면, 다음과 같이 하면 실행파일의 이름을 가지고 core 파일의 이름을 만들 수 있다 :

# cat > /proc/sys/kernel/core_pattern
core.%e
^D
# 
저와 같이 해 두고 아까 컴파일한 파일을 실행시켜 보면,
$ ./a.out 
hello
Segmentation fault (core dumped)
$ ls
a.c  a.out*  core.a.out
$

참고 및 인용사이트 : http://altibase.tistory.com/241

Posted by 라판

보통 core파일은 응용 프로그램가 crash날 때, 사용되곤 한다. 

그런데 만약 커널 패닉이 발생하는 상황은 어덯게 대처해야 할까? 

커널 패닉의 경우에도 core 파일이 생기며, vmcore라는 이름으로 아래 경로에

생기는 듯 하다. 

/var/crash/xxxx-xx-xx-xx:xx:xx/vmcore


그렇다면 이를 어떻게 분석할 수 있을까?

아래와 같이 crash 명령어를 사용하여 분석할 수 있다. 


출처 - http://joonlinux.blogspot.kr/2011/02/blog-post.html

리눅스 커널 코어 덤프 분석하기 


1. 커널 코어 분석 유틸리티 설치하기

 yum install --enablerepo=rhel-debuginfo crash kernel-debuginfo

2.커널 코어덤프 파일 분석 시작 하기

crash /usr/lib/debug/lib/modules/<커널 릴리즈 버전>/vmlinux \
/var/crash/xxxx-xx-xx-xx:xx:xx/vmcore

3.커널 메세지 버퍼내용 확인하기
crash > log

4.커널 satck trace  정보 확인하기
crash > bt

5. 프로세서 상태 확인하기
crash > ps

6. virtual memory 정보 확인하기
crash > vm

7. open file 확인하기
crash > files

- crash 명령 소개 

sys - 시스템의 일반적인 정보를 출력해 준다.
bt - Backtrace 명령. 스택의 내용들을 순차적으로 출력해준다.
ps - Process list 출력.
free - Memory 및 스왑 상태 출력.
mount - 마운트 상태 출력
irq - 각 장치의 ( irq ) 상태를 출력.
kmem - 메모리 상태 출력 ( kmalloc, valloc 등 메모리 할당 상태도 보여줌 )
log - dmesg 의 내용을 출력.
mod - 로딩된 모듈 리스트 출력.
net - Network 상태 출력.
runq - 실행중인 task 리스트 출력.
task - 작업목록 출력.
rd - 메모리 번지수에 대한 상세정보 출력.
foreach - 모든 task, process 등 디버깅 정보에 대한 상세한 출력이 가능함.
set - 설정된 주소 및 PID 등을 기본 컨텍스트로 설정.
struct - 구조화된 메모리 내부의 변수들을 출력해 준다.
files - task 가 열고있는 파일디스크립터들을 출력해준다.

또는, 아래의 문서를 참고하면 좋을 듯 하다 
출처 - http://cafe.daum.net/redhat/COsR/29?docid=1HjQ8COsR2920090904142417

 Kernel_Dump_Analysis.pdf

Posted by 라판

출처 - http://wiki.kldp.org/HOWTO//html/Adv-Bash-Scr-HOWTO/internal.html


11장. 내부 명령어(Internal Commands and Builtins)

내부 명령(builtin) 은 Bash 툴 셋에 포함된 명령어로 말 그대로 bulit in(고유의, 붙박이의)된 명령어입니다. 내부 명령은 시스템 명령어와 이름이 같을 수도 있지만 이런 경우는 Bash가 내부적으로 다시 구현해 놓은 것입니다. [1] 예를 들어, 하는 일이 거의 동일한 bash의 echo는 /bin/echo와 다릅니다.

키워드(keyword)는 예약된 낱말, 토큰, 연산자를 말합니다. 키워드는 쉘에서 특별한 의미를 가지면서, 쉘 문법을 형성해 줍니다. 예를 들면, "for""while""!"가 키워드입니다. 내부 명령(builtin)과 비슷하게 키워드도 Bash 내부에 하드코드(hard-coded)되어 있습니다.

I/O

echo

변수나 표현식을 표준출력으로 출력(예 5-1 참고).

echo Hello
echo $a

echo 에서 이스케이프 문자들을 찍으려면 -e 옵션을 주어야 합니다. 예 6-2를 참고하세요.

보통, 각각의 echo는 뉴라인을 출력해 주지만 -n 옵션을 주면 이 뉴라인을 안 찍어 줍니다.

참고: echo는 파이프에서 여러 명령어중의 하나로 쓰일 수 있습니다.

if echo "$VAR" | grep -q txt   # if [[ $VAR = *txt* ]]
then
  echo "$VAR 에는 \"txt\"" 문자열이 들어 있습니다."
fi

참고: echo를 명령어 치환과 같이 써서 변수 값을 세트할 수 있습니다.

a=`echo "HELLO" | tr A-Z a-z`

예 12-15예 12-2예 12-28예 12-29를 참고하세요.

경고

echo `command`는 command 출력의 모든 라인피드를 지워버리는 것에 주의하기 바랍니다. 보통 \n이 $IFS의 공백문자중 하나이기 때문에, Bash는 command의 출력에 나타나는 라인피드를 빈 칸으로 바꾸어 echo의 인자로 만들어 버립니다.

bash$  printf '\n\n1\n2\n3\n\n\n\n'

 1
 2
 3



bash $




bash$ echo "`printf '\n\n1\n2\n3\n\n\n\n'`"

 1
 2
 3
bash $
	      

참고: 이 명령어는 쉘 내장 명령으로서 /bin/echo와 비슷한 동작을 하지만 엄연히 다릅니다.

bash$ type -a echo
echo is a shell builtin
echo is /bin/echo
	      

printf

printf는 형식화된 출력을 해주는 명령어로서, echo의 확장판입니다. C 언어의 printf보다 기능이 제한된 변종으로, 문법은 C와 약간 다릅니다.

printf format-string... parameter...

/bin/printf나 /usr/bin/printf의 bash 내장 명령 버전입니다. 더 자세한 내용은 printf(시스템 명령어)의 맨 페이지를 참고하세요.

경고

bash의 옛날 버전은 printf를 지원하지 않을 수도 있습니다.

예 11-1. printf가 실제로 쓰이는 예제

#!/bin/bash
# printf demo

PI=3.14159265358979
DecimalConstant=31373
Message1="안녕들 하신가,"
Message2="지구인 여러분."

echo

printf "Pi를 소수점 이하 2 자리만 표시 = %1.2f" $PI
echo
printf "Pi를 소수점 이하 9 자리만 표시 = %1.9f" $PI  # 반올림이 잘 됐죠?

printf "\n"                                  # 라인피드를 찍음.
                                             # 'echo'와 똑같음.

printf "상수 = \t%d\n" $DecimalConstant  # 탭이 들어갔죠(\t)

printf "%s %s \n" $Message1 $Message2

echo

# ==========================================#
# C 함수인 'sprintf'를 시뮬레이션.
# 형식화된 문자열로 변수를 로딩.

echo 

Pi12=$(printf "%1.12f" $PI)
echo "Pi를 소수점 12 자리만 표시 = $Pi12"

Msg=`printf "%s %s \n" $Message1 $Message2`
echo $Msg; echo $Msg

# 이렇게 하면, 'sprintf' 함수는 Bash에서 로딩할 수 있는 모듈로
# 접근이 가능해 지지만, 이식성이 있는 구현은 아닙니다.

exit 0

printf는 에러 메세지를 형식화 해서 출력해 줄 때 아주 유용하게 쓰입니다.

E_BADDIR=65

var=nonexistent_directory

error()
{
  printf "$@" >&2
  # 인자로 넘어온 위치 매개변수를 형식화해서 표준에러로 출력
  echo
  exit $E_BADDIR
}

cd $var || error $"%s 로 바꿀 수 없습니다." "$var"

# Thanks, S.C.

read

변수값을 표준입력에서 "읽어 들입니다." 즉, 키보드에서 사용자의 입력을 받아 처리합니다. -a 옵션을 주면 read는 변수를 배열로 받아 들입니다(예 26-2 참고).

예 11-2. read로 변수 할당하기

#!/bin/bash

echo -n "'var1' 변수값을 넣으세요: "
# -n 옵션은 뉴라인을 제거해 줍니다.

read var1
# var1 변수가 read에 의해 세트되기 때문에 var1 앞에 '$'가 없습니다. 주의하세요.

echo "var1 = $var1"


echo

# 하나의 'read' 문으로 여러개의 변수를 세트할 수 있습니다.
echo -n "'var2'와 'var3'의 값을 넣으세요(빈 칸이나 탭으로 구분): "
read var2 var3
echo "var2 = $var2      var3 = $var3"
# 한 개 값만 주게 되면, 다른 변수(들)은 세트가 안 된 상태(널)로 남게 됩니다.

exit 0

read로 입력을 넣을 때 보통은 뉴라인 전에 \를 넣어 뉴라인을 무시하게 합니다. -r 옵션을 주면 \ 가 문자 그대로 해석되도록 합니다.

예 11-3. read로 여러줄의 입력 넣기

#!/bin/bash

echo

echo "\\ 로 끝나는 문자열을 입력하고 <ENTER> 를 누르세요."
echo "그 다음에 두 번째 문자열을 입력하고 <ENTER> 를 다시 누르세요."
read var1     # "var1"을 읽을 때 "\" 때문에 뉴라인이 제거됩니다.
              #     첫번째 줄 \
              #     두번째 줄

echo "var1 = $var1"
#     var1 = 첫번째 줄 두번째 줄

# "\"로 끝나는 줄을 만날 때 마다,
# var1에 문자를 계속 입력하기 위해서 다음 줄을 위한 프롬프트를 받게 됩니다.

echo; echo

echo "\\ 로 끝나는 다른 문자열을 입력하고 <ENTER> 를 누르세요."
read -r var2  # -r 옵션은 "\"를 문자 그대로 읽어 들입니다.
              #     첫번째 줄 \

echo "var2 = $var2"
#     var2 = 첫번째 줄 \

# 입력 데이타는 첫번째 <ENTER> 에서 끝나게 됩니다.

echo 

exit 0

read 명령어는 프롬프트를 보여준 다음 ENTER없이 키누름을 받아 들이는 재밌는 옵션을 갖고 있습니다.

# ENTER 없이 키누름을 읽음.

read -s -n1 -p "키를 누르세요 " keypress
echo; echo "당신이 누른 키는 "\"$keypress\""입니다."

# -s 는 입력을 에코하지 말라는 옵션입니다.
# -n N 은 딱 N 개의 문자만 받아 들이라는 옵션입니다.
# -p 는 입력을 읽기 전에 다음에 나오는 프롬프트를 에코하라는 옵션입니다.

# 이 옵션들은 순서가 바로 되어 있어야 하기 때문에 쓰기가 약간 까다롭습니다.

read 명령어는 표준입력으로 재지향된 파일에서 변수값을 "읽을" 수도 있습니다. 입력 파일이 한 줄 이상이라면 첫 번째 줄만 변수로 할당됩니다. read가 하나 이상의 매개변수를 갖고 있다면 각 변수는 공백 문자로 구분되는 연속적인 문자열로 할당됩니다. 조심하세요!

예 11-4. read를 파일 재지향과 같이 쓰기

#!/bin/bash

read var1 <data-file
echo "var1 = $var1"
# "data-file"의 첫번째 줄 전체가 var1으로 세팅

read var2 var3 <data-file
echo "var2 = $var2   var3 = $var3"
# "read"의 직관적이지 않은 행동에 주의하세요.
# 1) 입력 파일의 제일 처음으로 돌아가서,
# 2) 각 변수는 줄 전체가 아닌 공백문자로 나누어진 문자열로 세트됨.
# 3) 마지막 변수는 그 줄의 나머지로 세트.
# 4) 변수 갯수가 공백문자로 나누어진 문자열보다 많다면 나머지 변수들은 세트되지 않음.

echo "------------------------------------------------"

# 위의 문제를 루프로 해결해 보겠습니다.
while read line
do
  echo "$line"
done <data-file
# Heiner Steven 이 이 부분을 지적해 주었습니다.

echo "------------------------------------------------"

# "read"가 읽어 들이는 줄이 공백문자가 아닌 다른 문자로 구분되도록 하려면
# $IFS(내부 필드 구분자, Internal Field Separator)를 쓰면 됩니다.

echo "모든 사용자 목록:"
OIFS=$IFS; IFS=:       # /etc/passwd 는 필드 구분자로 ":"를 씁니다.
while read name passwd uid gid fullname ignore
do
  echo "$name ($fullname)"
done </etc/passwd   # I/O 재지향.
IFS=$OIFS              # 원래 $IFS 를 복구시킴.
# 이 코드도 Heiner Steven 이 제공해 주었습니다.

exit 0

파일시스템

cd

익숙한 명령어인 cd는 스크립트에서 어떤 명령어가 특정한 디렉토리에서 실행될 필요가 있을 때 그 디렉토리로 옮겨가기 위해 쓰입니다.

(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)
[앞서 인용했던 알란 콕스의 예제]

cd가 심볼릭 링크를 무시하고 원래 디렉토리로 가도록 하기 위해서는 -P(물리적인, physical) 옵션을 주면 됩니다.

cd - 라고 하면 바로 전 작업 디렉토리인 $OLDPWD 로 옮겨 갑니다.

pwd

현재 작업 디렉토리를 출력(Print Working Directory). 이 명령어는 사용자(혹은 스크립트)의 현재 디렉토리(예 11-5 참고)를 알려줍니다. 내부 변수인 $PWD의 값을 읽는 것과 동일한 효과를 가져옵니다.

pushdpopddirs

이 명령어들은 작업 디렉토리를 즐겨찾기에 기억시켜주는 메카니즘으로, 디렉토리간에 순서대로 왔다 갔다 할 수 있게 해 줍니다. 디렉토리 이름을 기억하기 위해서 푸쉬다운 스택을 사용합니다. 옵션을 줘서 디렉토리 스택에 대해서 다양한 조작을 할 수 있습니다.

pushd dir-name은 dir-name을 디렉토리 스택에 넣고 동시에 현재 디렉토리를 그 디렉토리로 옮겨 줍니다.

popd는 디렉토리 스택의 제일 위에 있는 디렉토리를 지우고(pop) 동시에 현재 디렉토리를 그 디렉토리로 옮겨 줍니다.

dirs은 디렉토리 스택의 목록을 보여줍니다 ($DIRSTACK과 같음). pushd나 popd가 성공한다면 dirs가 자동으로 불립니다.

디렉토리 이름을 하드 코딩하지 않고 디렉토리를 여기 저기로 옮겨 다녀야 하는 스크립트가 이 명령어를 쓰면 아주 좋습니다. 스크립트 내에서 디렉토리 스택의 내용을 담고 있는 $DIRSTACK 배열 변수에 묵시적으로 접근이 가능하기 때문에 주의해야 합니다.

예 11-5. 현재 작업 디렉토리 변경하기

#!/bin/bash

dir1=/usr/local
dir2=/var/spool

pushd $dir1
# 자동으로 'dirs'를 실행합니다(디렉토리 스택의 내용을 표준출력으로 뿌림).
echo "Now in directory `pwd`." # 역따옴표(backquote)를 건 'pwd'.

# 'dir1'에서 아무 일이나 하고,
pushd $dir2
echo "지금은 `pwd` 디렉토리에 있습니다."

# 'dir2'에서 아무 일이나 한 다음,
echo "DIRSTACK 배열의 top 항목은 $DIRSTACK 입니다."
popd
echo "이제 `pwd` 디렉토리로 돌아왔습니다."

# 'dir1'에서 아무 일이나 하세요.
popd
echo "이제 원래의 `pwd` 디렉토리로 돌아왔습니다."

exit 0

변수

let

let 명령어는 변수에 대해서 산술 연산을 수행합니다. 많은 경우에 있어서 expr보다 좀 간단한 기능을 수행합니다.

예 11-6. let으로 몇 가지 산술 연산을 하기.

#!/bin/bash

echo

let a=11          # 'a=11' 과 똑같습니다.
let a=a+5         # let "a = a + 5" 와 똑같습니다.
                  # (큰따옴표와 빈 칸을 쓰면 좀 더 읽기가 편하죠)
echo "11 + 5 = $a"

let "a <<= 3"     # let "a = a << 3" 과 똑같습니다.
echo "\"\$a\" (=16) 를 3 번 왼쪽 쉬프트 = $a"

let "a /= 4"      # let "a = a / 4" 와 똑같습니다.
echo "128 / 4 = $a"

let "a -= 5"      # let "a = a - 5" 와 똑같습니다.
echo "32 - 5 = $a"

let "a = a * 10"  # let "a = a * 10" 과 똑같습니다.
echo "27 * 10 = $a"

let "a %= 8"      # let "a = a % 8" 과 똑같습니다.
echo "270 modulo 8 = $a  (270 / 8 = 33, 나머지는 $a)"

echo

exit 0
eval

eval arg1 [arg2] ... [argN]

목록에 들어 있는 인자를 명령어로 변환(스크립트 안에서 코드를 만들어 낼 때 유용함).

예 11-7. eval의 효과 보여주기

#!/bin/bash

y=`eval ls -l`   # y=`ls -l` 과 비슷하지만,
echo $y          # 라인피드가 지워집니다.

y=`eval df`      # y=`df` 와 비슷하지만,
echo $y          # 라인피드가 지워집니다.

# 라인피드(LF)가 없어지기 때문에 출력을 파싱하기가 더 쉬울 것입니다.

exit 0

예 11-8. 강제로 로그 아웃 시키기

#!/bin/bash

y=`eval ps ax | sed -n '/ppp/p' | awk '{ print $1 }'`
# 'ppp'의 프로세스 번호를 찾은 다음,

kill -9 $y   # 죽이고,

# 위에서 한 것은 다음처럼 해도 됩니다.
#  kill -9 `ps ax | awk '/ppp/ { print $1 }'


chmod 666 /dev/ttyS3
# ppp에 SIGKILL을 날리면 직렬 포트의 퍼미션이 바뀌기 때문에
# 이전 퍼미션으로 복구시켜야 됩니다.

rm /var/lock/LCK..ttyS3   # 직렬 포트용 잠금 파일을 지웁니다.

exit 0

예 11-9. "rot13" 버전

#!/bin/bash
# 'eval'로 "rot13"을 구현.
# (옮긴이: rot13 이란 각 알파벳을 13번 로테이트(그래서 이름이 rot13) 시키는 
# 간단한 암호화입니다.)
# "rot13.sh" 예제와 비교해 보세요.

setvar_rot_13()              # "rot13" 스크램블(암호화)
{
  local varname=$1 varvalue=$2
  eval $varname='$(echo "$varvalue" | tr a-z n-za-m)'
}


setvar_rot_13 var "foobar"   # "foobar" 를 rot13 시키면,
echo $var                    # sbbone

echo $var | tr a-z n-za-m    # foobar
                             # 원래 변수로 되돌림.

# Stephane Chazelas 제공.

exit 0

경고

eval 명령어는 아주 위험한 상황을 가져올 수 있기 때문에 합당한 다른 방법이 있다면 이것을 쓰지 않는 것이 좋습니다. eval $COMMANDS는 rm -rf * 처럼 유쾌하지 않은 값을 갖고 있을 수도 있는 COMMANDS을 실행 시킵니다. 모르는 사람이 작성한 잘 모르는 코드에 대해서 eval를 실행 시키는 것은 아주 위험합니다.

set

set 명령어는 내부 스크립트 변수값을 바꿔줍니다. 스크립트의 행동을 결정하는 옵션 플래그를 키거나 끄는 역할에 쓰이기도 하고 특정 명령어의 결과(set `command`)를 위치 매개변수로 리셋 시켜서 스크립트가 그 명령어의 결과를 필드별로 파싱할 수 있게 해 줍니다.

예 11-10. 위치 매개변수와 set 쓰기

#!/bin/bash

# "set-test" 스크립트

# 3개의 인자를 줘서 실행시키세요.
# 예를 들면, "./set-test one two three".

echo
echo "set \`uname -a\` 하기 전의 위치 매개변수:"
echo "첫번째 명령어줄 인자 = $1"
echo "두번째 명령어줄 인자 = $2"
echo "세번째 명령어줄 인자 = $3"

echo

set `uname -a` # `uname -a` 의 출력을 위치 매개변수로 세트

echo "set \`uname -a\` 한 다음의 위치 매개변수:"
# $1, $2, $3... 이 `uname -a` 의 결과로 다시 초기화됩니다.
echo "'uname -a' 의 첫번째 필드 = $1"
echo "'uname -a' 의 두번째 필드 = $2"
echo "'uname -a' 의 세번째 필드 = $3"
echo

exit 0

예 10-2 참고.

unset

unset 명령어는 쉘 변수를 효과적으로 (null)로 세트를 해서 그 변수를 지우는 효과를 가져옵니다. 이 명령어는 위치 매개변수에 대해서 동작하지 않는 것에 주의하세요.

bash$ unset PATH

bash$ echo $PATH


bash$ 

예 11-11. 변수를 "언셋"(unset) 하기

#!/bin/bash
# unset.sh: 변수를 언셋하기.

variable=hello                       # 초기화.
echo "variable = $variable"

unset variable                       # 언셋.
                                     # variable=   라고 하는 것과 동일
echo "(unset) variable = $variable"  # $variable 는 널.

exit 0
export

export 명령어는 현재 실행중인 스크립트나 쉘의 모든 자식 프로세스가 변수를 사용할 수 있게 해 줍니다. 불행하게도 스크립트나 쉘을 부른 부모 프로세스에게 변수를 다시 export 할 방법은 없습니다. export는 시스템 구동(startup) 파일에서 환경 변수를 초기화하고 그 다음에 생성될 사용자 프로세스들이 그 변수에 접근할 수 있게 해주는 아주 중요한 용도로 쓰입니다.

예 11-12. export를 써서, 내장된 awk 스크립트에 변수를 전달하기

#!/bin/bash

# "column totaler" 스크립트(col-totaler.sh)의 또 다른 버전.
# 대상 파일의 주어진 지정된 컬럼을 모두 더해줌.
# 여기서는 스크립트 변수를 'awk'에게 전달하기 위해서 환경(environment)을 사용합니다.

ARGS=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # 원하는 수 만큼의 명령어줄 인자가 넘어왔는지 확인.
then
   echo "사용법: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

#===== 여기까지는 원래 스크립트와 똑같습니다 =====#

export column_number
# column_number 를 환경으로 export 해서 awk 스크립트에서 다시 꺼내갈수 있게 함.


# awk 스크립트 시작.
# ------------------------------------------------
awk '{ total += $ENVIRON["column_number"]
}
END { print total }' $filename
# ------------------------------------------------
# awk script 끝.


# Stephane Chazelas 제공.

exit 0

작은 정보: export var1=xxx라고 해서 초기화와 export를 한번에 할 수도 있습니다.

declaretypeset

declare 와 typeset 명령어는 변수의 특성을 지정하거나 제한해 줍니다.

readonly

declare -r과 같은 역할을 하는 명령어로서, 어떤 변수를 읽기 전용으로 만들어 주는 것인데, 결국 상수로 쓰겠다는 것입니다. 이런 변수값을 바꾸려고 한다면 에러 메세지를 만나게 됩니다. C 언어의 const 형지정자와 비슷한 것으로 보면 됩니다.

getopts

이것은 아주 강력한 도구로서 명령어 줄에서 스크립트로 넘어온 인자를 파싱해 줍니다. C 프로그래머들에게 익숙한 getopt 라이브러리 함수의 bash 버전입니다. 스크립트로 넘어오는 여러개의 옵션 [2] 과 그 해당 인자들을 처리해줍니다(예를 들면, scriptname -abc -e /usr/local).

getopts는 내부적으로 두 개의 변수를 사용합니다. $OPTIND(OPTion INDex)는 인자 포인터이고 $OPTARG(OPTion ARGument)는 옵션에 딸려 넘어오는 해당 인자(선택적)입니다. 선언 태그의 옵션 이름뒤에 콜론이 있으면 해당 인자가 있다는 뜻입니다.

getopts는 보통 while 루프와 같이 써서 옵션과 인자를 한 번에 하나씩 처리하고 $OPTIND 변수값을 하나씩 줄여서 그 다음을 처리하게 합니다.

참고:

  1. 명령어 줄에서 인자앞에는 빼기(-)나 더하기(+)를 적어 줘야 하는데 이 접두사가 있어야 getopts가 명령어 줄 인자를 옵션으로 인식할 수 있습니다. 실제로는, -나 +가 빠져 있는 첫번째 인자를 만나면 바로 종료하게 됩니다.

  2. getops는 표준 while 루프와 약간 다른 형태로 조건 대괄호가 빠져 있는 형태입니다.

  3. 예전의 getopt 대신 getopts가 새롭게 쓰입니다.

while getopts ":abcde:fg" Option
# 초기 선언.
# a, b, c, d, e, f, g 옵션(플래그)만 지원.
# 'e' 뒤의 :로 'e' 옵션에는 인자가 있어야 된다는 것을 나타냄
do
  case $Option in
    a ) # 'a'일 경우 할 일.
    b ) # 'b'일 경우 할 일.
    ...
    e)  # 'e'일 경우 할 일, $OPTARG 로 'e' 뒤에 따라오는 해당 인자를 처리.
    ...
    g ) # 'g'일 경우 할 일.
  esac
done
shift $(($OPTIND - 1))
# 인자 포인터를 다음으로 이동.

# 보이는 것처럼 그렇게 복잡하지는 않습니다. <씨익>.
	      

예 11-13. getopts로 스크립트로 넘어온 옵션과 인자 읽기

#!/bin/bash

# 'getopts' 는 스크립트로 넘어온 명령어줄 인자를 처리해 줍니다.
# 인자들은 "옵션"(플래그)과 해당 인자로 파싱됩니다.

# 이렇게 실행시켜 보세요.
# 'scriptname -mn'
# 'scriptname -oq qOption' (qOption 은 아무런 문자열이면 됩니다.)
# 'scriptname -qXXX -r'
#
# 'scriptname -qr'    - 원하던 결과가 안 나오는데, "r"이 "q" 옵션의 추가 인자로 처리되기 때문입니다.
# 'scriptname -q -r'  - 위와 똑같이 원치 않는 결과.
# 어떤 옵션에 추가 인자("flag:")가 필요하다고 설정이 되면 
# 명령어줄에서 자기 바로 다음에 나오는 것을 무조건 자신의 인자로 받아들입니다.

NO_ARGS=0 
OPTERROR=65

if [ $# -eq "$NO_ARGS" ]  # 인자 없이 불렸군요.
then
  echo "사용법: `basename $0` options (-mnopqrs)"
  exit $OPTERROR          # 인자가 주어지지 않았다면 사용법을 알려주고 종료.
fi  
# 사용법: scriptname -options
# 주의: 대쉬(-)가 필요합니다.


while getopts ":mnopq:rs" Option
do
  case $Option in
    m     ) echo "1번 시나리오: option -m-";;
    n | o ) echo "2번 시나리오: option -$Option-";;
    p     ) echo "3번 시나리오: option -p-";;
    q     ) echo "4번 시나리오: option -q-, \"$OPTARG\"를 줘서";;
    # 'q' 옵션은 추가 인자가 있어야 하는데 없다면 디폴트로 처리됩니다.
    r | s ) echo "5번 시나리오: option -$Option-"'';;
    *     ) echo "구현되지 않은 옵션이 선택됐습니다.";;   # 디폴트
  esac
done

shift $(($OPTIND - 1))
# 인자 포인터를 감소시켜서 다음 인자를 가르키게 합니다.

exit 0

스크립트 동작

source. ((dot) 명령어)

이 명령어가 명령어 줄에서 불린다면 해당 스크립트를 실행 시킵니다. 스크립트에서 source file-name이라고 불린다면 file-name을 읽어 들일 것입니다. C/C++의 #include 지시자와 같은 역할을 합니다. 여러개의 스크립트가 공통으로 쓰이는 데이타 파일이나 함수 라이브러리를 써야 할 경우같은 상황에서 유용합니다.

예 11-14. 데이타 파일 "포함하기"

#!/bin/bash

. data-file    # 데이타 파일 로드.
# "source data-file"이라고 하는 것과 같지만, 이게 좀 더 이식성 있는 방법입니다.

# "data-file"은 'basename'으로 참조되기 때문에 현재 디렉토리에 꼭 있어야 됩니다.

# 이제 그 파일에 들어 있는 몇개의 데이타를 참조해 보겠습니다.

echo "variable1 (data-file 에 있는 변수) = $variable1"
echo "variable3 (data-file 에 있는 변수) = $variable3"

let "sum = $variable2 + $variable4"
echo "variable2 + variable4 (data-file 에 있는 변수) = $sum"
echo "message1 (data-file 에 있는 변수) 은 \"$message1\""
# 주의:                                    이스케이프된 쿼우트

print_message 이것은 data-file 의 message-print 함수가 보여주는 메세지입니다.


exit 0

위의 예 11-14에서 data-file은 같은 디렉토리에 있어야 합니다.

# error free
# (옮긴이:
# 제일 윗줄에 한글이 들어가 있으면 file data-file 이라고 했을 때 
# data-file: International language text
# 라고 나오네요. 이것 때문인지 예제에서 이 파일을 . 하면 에러가 납니다.
# 맨 위의 error free 는 이 에러를 피하기 위한 것입니다.)
#
#
# 이것은 스크립트에 의해 읽히는 데이타 파일입니다.
# 이런 종류의 파일은 보통 변수나 함수등을 담고 있습니다.
# 쉘 스크립트에 의해 'source'나 '.'로 적재될 수 있습니다.

# 변수를 초기화 합시다.

variable1=22
variable2=474
variable3=5
variable4=97

message1="안녕, 잘 지냈어?"
message2="이젠 됐어. 안녕."

print_message ()
{
# 넘어온 어떤 메세지도 다 에코시킴.

  if [ -z "$1" ]
  then
    return 1
    # 인자가 없으면 에러.
  fi

  echo

  until [ -z "$1" ]
  do
    # 함수로 넘어온 인자를 하나씩 모두 처리.
    echo -n "$1"
    # 라인 피드를 없애면서 한 번에 하나씩 에코.
    echo -n " "
    # 낱말 사이에 빈 칸을 집어 넣음.
    shift
    # 다음.
  done  

  echo

  return 0
}  
exit

스크립트를 무조건 끝냄. exit는 정수값을 인자로 받아서 쉘에게 스크립트의 종료 상태를 알려줄 수도 있습니다. 아주 간단한 스크립트가 아니라면 스크립트의 마지막에 exit 0처럼 성공적인 실행을 알려 주는 것은 아주 좋은 습관입니다.

참고: 만약에 exit가 인자 없이 쓰인다면 그 스크립트의 종료 상태는 exit를 제외하고 가장 마지막에 실행된 명령어의 종료 상태로 됩니다.

exec

이 쉘 내부 명령은 현재의 프로세스를 주어진 명령어로 대치시킵니다. 보통은 쉘이 어떤 명령어를 만나면 그 명령어를 실행하기 위해서 자식 프로세스를 포크 [3] 시킵니다. 하지만 exec 내장 명령은 포크를 하지 않고 exec된 그 명령어로 쉘 자체를 대치시킵니다. 그렇기 때문에 스크립트에서 이 명령어가 쓰이면 exec된 명령어가 종료할 때 스크립트가 강제로 종료됩니다. 이런 이유로, exec을 스크립트에서 쓰려면 아마도 제일 마지막 명령어로 써야 할 겁니다.

exec는 또한 파일 디스크립터를 재할당 할 때도 쓰입니다. exec <zzz-file은 표준입력을 zzz-file으로 바꿔줍니다(예 16-1 참고).

예 11-15. exec 효과

#!/bin/bash

exec echo "\"$0\" 를 종료합니다."   # 스크립트에서 종료.

# 다음 줄은 절대 실행되지 않습니다.

echo "여기는 절대 에코되지 않습니다."

exit 0  # 역시, 여기서 종료되지도 않고요.

참고: find 명령어의 -exec 옵션은 exec 쉘 내장 명령과 다릅니다.

shopt

이 명령어는 쉘이 실행중에 옵션을 바꿀 수 있게 해 줍니다(예 24-1과 예 24-2 참고). 이는 종종 Bash 시스템 구동 파일(startup files)에서 쓰이는 데 일반 스크립트에서도 쓰일 수 있습니다. 이 명령어는 bash 버전 2나 그 다음 버전부터 쓸 수 있습니다..

shopt -s cdspell
# 'cd'를 쓸 때 디렉토리 이름이 약간 틀린 것 정도는 자동으로 고쳐줍니다.

명령어

true

단순히 성공적(0)인 종료 상태를 리턴하는 명령어.

# 무한 루프
while true   # ":" 의 별칭(alias)
do
   operation-1
   operation-2
   ...
   operation-n
   # 루프를 빠져 나갈 방법이 필요.
done

false

단순히 실패한 종료 상태를 리턴하는 명령어.

# 널 루프
while false
do
   # 이 부분은 실행되지 않음.
   operation-1
   operation-2
   ...
   operation-n
   # 아무 일도 안 일어납니다!
done   

type [cmd]

외부 명령어인 which와 비슷하게 주어진 "cmd"의 완전한 경로명을 보여 줍니다. 하지만, which와는 다르게 type는 bash 내장 명령입니다. 유용한 옵션인 -a를 주면 주어진 "cmd"가 키워드인지 내장 명령인지를 알려주고 똑같은 이름의 시스템 명령어가 있다면 그 위치도 알려줍니다.

bash$ type '['
[ is a shell builtin
bash$ type -a '['
[ is a shell builtin
[ is /usr/bin/[
	      

hash [cmds]

주어진 명령어의 경로명을 쉘 해쉬 테이블에 저장해서 그 명령어가 다시 불릴 때 $PATH에서 찾지 않도록 해줍니다. hash를 인자 없이 쓰면 자신이 해쉬하고 있는 목록을 보여줍니다. -r 옵션은 해쉬 테이블을 초기화 합니다.

help

help 명령어는 쉘 내장 명령에 대한 간략한 사용법을 알려줍니다. whatis와 동일하지만 내장 명령에 대해서 쓰인다는 점이 다릅니다.

bash$ help exit
exit: exit [n]
    Exit the shell with a status of N.  If N is omitted, the exit status
    is that of the last command executed.
	      

주석

[1]

이렇게 하는 이유는 성능상의 문제(보통은 fork를 해야 하는 외부 명령어보다 더 빠르게 실행)이거나 특정 내부 명령의 경우에 쉘 내부 변수로 직접 접근할 필요가 있기 때문입니다.

[2]

옵션은 플래그처럼 동작하는 인자로서 스크립트의 행동을 키거나 꺼 줍니다. 특정 옵션과 관련이 있는 인자는 그 옵션(플래그)이 나타내는 행동을 키거나 끄게 합니다.

[3]

명령어나 쉘 자신이 어떤 작업을 수행하기 위해 새로운 하위 프로세스를 초기화(혹은 spawn)하는 것을 포크(fork)라고 합니다. 이 때, 새롭게 생긴 프로세스를 "자식" 프로세스라고 하고, 그 자식 프로세스를 포크한 프로세스를 "부모" 프로세스라고 합니다. 자식 프로세스가 자신에게 주어진 일을 하는 동안 부모 프로세스도 계속 자신의 일을 해 나갑니다.

'리눅스 > 일반' 카테고리의 다른 글

NFS daemon 수 수정  (0) 2013.01.16
Bash 내부 명령어  (0) 2012.10.18
Bash 외부 명령어  (0) 2012.10.18
Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
Posted by 라판

출처 - http://wiki.kldp.org/HOWTO//html/Adv-Bash-Scr-HOWTO/external.html

kldp에 있던 명령어 모음.

대충 살펴보니, 리눅스 shell에서 사용하는 웬만한 명령어는 모두 포함되어 있다. 

참고하면 매우 좋을 듯 

12장. 외부 필터, 프로그램, 명령어

유닉스 표준 명령어들은 쉘 스크립트를 좀 더 융통성 있게 만들어 줍니다. 스크립트의 막강한 힘은 시스템 명령어들과 간단한 프로그래밍 구조로 된 쉘 지시자들에서 나옵니다.

'리눅스 > 일반' 카테고리의 다른 글

NFS daemon 수 수정  (0) 2013.01.16
Bash 내부 명령어  (0) 2012.10.18
Bash 외부 명령어  (0) 2012.10.18
Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
Posted by 라판

Redirection

리눅스/일반 2012.10.18 16:15

출저 : http://radiocom.kunsan.ac.kr/lecture/unix_cmd/redirection.html


재지정(redirection)이란?

표준입력, 표준출력, 표준 에러 출력을 다시 지정함

유닉스에서 모든 프로그램이 실행 될 때 최소 3 개의 파일을 입출력 용도로 지정해서 쓰고 있으며 각각에 대해 숫자를 하나씩 할당하여 관리하고 있다.
실행 파일의 입출력 용도로 쓰이는 파일에 할당한 숫자를 파일 디스크립터(fd: file descriptor)라 하며 숫자로 할당해서 사용하고 있다.

fd디스크립터 이름용도표준 장치
0stdin(standard input)명령어에 입력될 내용이 저장되어 있는 파일키보드
1stdout(standard output)명령어에서 출력될 내용이 담길 파일화면
2stderr(standard error)명령어에서 출력될 에러 메시지가 담길 파일화면, /dev/null

이렇게 명령어에 입출력으로 사용되는 장치를 표준장치가 아닌 파일로 재지정하는 것을 입출력 재지정이라 한다.
입출력 재지정에는 <기호와 >기호가 사용된다. 
<기호는 입력 재지정에 쓰이고, >기호는 출력 재지정에 사용된다.

형식의미
명령 < 파일이름명령어 내부에서 지정한 파일에서 데이터를 읽는 것이 아니라 "파일이름"의 파일에서 데이터를 읽어 들임
명령 > 파일이름명령어 내부에서 지정한 파일로 데이터를 기록하는 것이 아니라 "파일이름"의 파일에 데이터를 기록함

입출력 재지정을 나타내는 기호(>, <, >>) 앞에 적은 파일 디스크립터(0,1)를 생략할 수 있다. 따라서 입력 재지정에서 < 기호 다음에 파일이름을 적으면 키보드 대신 지정한 파일에서 데이터를 읽어 들이고, 출력 재지정에 > 기호 다음에 파일이름을 적으면 화면에 출력하는 대신 지정한 파일에 그 출력 결과를 기록한다.

• 입력 재지정에서 '0'이 생략되었다고 간주하고,

• 출력 재지정에서 '1'이 생략되었다고 간주한다.

따라서 입력 재지정에 <기호 다음에 파일이름을 적으면 키보드 대신 지정한 파일에서 데이터를 읽어 들이고, 출력 재지정에 >기호 다음에 파일이름을 적으면 화면에 출력지 않고 지정한 파일에 출력을 기록한다.

UNIX 쉘에서는 표준 입력인 stdin을 키보드로, 표준출력인 stdout을 모니터로, 그리고 표준 에러 출력인 stderr을 /dev/null로 설정되어 있음을 알 수 있다.
이 처럼 표준으로 지정된 입출력을 임의로 다시 지정하여 자신이 원하는 파일에 저장하거나, 또는 자신이 지정한 파일로 부터 읽어 들이도록 다시 지정하는 것을 redirection(재지정)이라 한다.

이렇게 입•출력 방향을 조정함으로써, 어떤 명령의 출력이 다른 명령의 입력으로, 또는 지정된 파일로 보낼 수 있다. 또한 입력의 경우도 키보드에서만 이루어지는 것은 아니고 다른 명령의 출력으로부터, 또는 파일로부터 입력될 수 있게 할 수 있어 재지정은 유닉스 쉘의 유용한 기능이라 할 수 있다.

기본적으로 stdin, stdout, stderr를 위해 오픈 되는 파일은 /dev/tty, 즉 자신의 터미널의 이름이다.
기본이 터미널이므로 사용자들은 프로그램에게 어디에서 읽고 어디에 쓰라고 지정할 필요가 없다.

모든 쉘들은 stdin, stdout, stderr에 대한 기본적인 리다이렉션을 제공한다. 다만 Bourne 쉘은 추가로 파일 디스크립터 번호를3에서 9까지 다룰 수 있다.

입력 재지정

입력 재지정의 형식은 다음과 같다.


명령 < 파일이름
명령 0< 파일이름

두 방법 모두 동일한 의미를 가지므로 첫 번째 방법을 권한다. 이는 두 번째 형식에 나오는 0이라는 숫자가 표준 입력을 의미하는 file descriptor이다.

입력 재지정에서 < 기호 앞의 숫자를 생략하면 0을 생략한 것으로 간주하기 때문에 0을 생략한 첫 방법을 널리 사용한다.

출력 재지정

출력 재지정의 형식은 다음과 같다.


명령 > 파일이름
명령 1> 파일이름
기존 파일이 없을 경우

명령 >> 파일이름
명령 1>> 파일이름
기존 파일이 있으면 추가하고,
없으면 새로 만들어 기록함

두 방법 모두 동일한 의미를 가지므로 첫 번째 방법을 권한다. 이는 두 번째 형식에 나오는 1이라는 숫자가 표준 출력을 의미하는 file descriptor이다.

출력 재지정에서 > 기호 앞의 숫자를 생략하면 1을 생략한 것으로 간주하기 때문에 1을 생략한 첫 방법을 널리 사용한다.

에러 재지정

에러 재지정의 형식은 다음과 같다.


명령 2> 파일이름
명령 2>> 파일이름

에러 재지정에서 file descriptor인 2를 생략하면 않된다.
2>은 새로 파일을 만들어 에러 메시지를 저장하고, 2>>은 파일이 존재하면 에러 내용을 그 파일에 추가 하고 파일이 존재하지 않으면 파일을 새로 만들어 오류 내용을 저장하라는 의미로 쓰인다.

출력과 에러 메시지를 동일 파일에 저장하는 경우

유닉스에서 출력과 에러 메시지를 동일 파일에 저장하여 사용하는 경우가 더 편리할 수 있으므로 다음과 같은 형식으로 사용한다.

다음 표에서 방법1과 방법2는 같다.

방법1방법2
명령 > 파일이름 2> 파일이름명령 1> 파일이름 2> 파일이름
명령 2> 파일이름 > 파일이름명령 2> 파일이름 1> 파일이름
명령 > 파일이름 2>&1명령 1> 파일이름 2>&1
명령 2> 파일이름 >&2명령 2> 파일이름 1>&2
명령 >> 파일이름 2>> 파일이름명령 1>> 파일이름 2>> 파일이름
명령 2>> 파일이름 >> 파일이름명령 2>> 파일이름 1>> 파일이름
명령 >> 파일이름 2>>&1 파일이름명령 1>> 파일이름 2>>&1 파일이름
명령 2>> 파일이름 >>&2 파일이름명령 2>> 파일이름 1>>&2 파일이름

>& 기호 앞과 뒤에 파일 디스크립터인 숫자를 붙여서 명시하여야 하는데, 앞의 파일 디스크립터가 1일 경우에는 생략해도 무방하다.
그러나 뒤의 파일 디스크립터 숫자가 1이면 반드시 명시해야 한다.

>& 기호는 뒤의 파일디스크립터가 저장하는 파일은 앞의 파일 디스크립터에서 명시한 파일을 사용한다는 의미를 가진다.
따라서 명령어 바로 앞의 > 기호 뒤의 파일에 출력 결과가 저장되는 효과가 있다.


【예제】 
% cat > temp     ☜ temp 파일은 존재하지 않음
이 글은 redirection을 이해하는 내용입니다.
temp 파일에 기록되며, 나중에 다시 사용할 것입니다.
Ctrl+d % cat temp
이 글은 redirection을 이해하는 내용입니다.
temp 파일에 기록되며, 나중에 다시 사용할 것입니다. % cat >> temp ☜ temp 파일이 이미 존재함
이 글은 두 번째 cat >> temp을 실행하여 temp 파일에 내용을 추가한다.
cat에서 끝낼 때는 ctrl+d를 누르면 종료됩니다.
Ctrl+d % cat temp
이 글은 redirection을 이해하는 내용입니다.
temp 파일에 기록되며, 나중에 다시 사용할 것입니다.
이 글은 두 번째 cat >> temp을 실행하여 temp 파일에 내용을 추가한다.
cat에서 끝낼 때는 ctrl+d를 누르면 종료됩니다. % mailx jijoe@it.kunsan.ac.kr < temp ☜ 파일 temp에서 읽어와 mailx를 실행함 % mailx % mailx jijoe@it.kunsan.ac.kr < temp % mailx
mailx version 5.0 Mon Nov 4 02:27:11 PST 2002 도움말을 보려면 ?를 입력하십시오.
"/var/mail//jijoe": 1개 메시지 1개 신규
>N 1 junik joe Fri May 25 11:38 19/827 ? 1
Message 1:
From jijoe@it.kunsan.ac.kr Fri May 25 11:38:23 2007
Date: Fri, 25 May 2007 11:38:22 +0900 (KST)
From: junik joe
To: jijoe@it.kunsan.ac.kr
이 글은 redirection을 이해하는 내용입니다.
temp 파일에 기록되며, 나중에 다시 사용할 것입니다.
이 글은 두 번째 cat >> temp을 실행하여 temp 파일에 내용을 추가한다.
cat에서 끝낼 때는 ctrl+d를 누르면 종료됩니다. ? d ? q %

'리눅스 > 일반' 카테고리의 다른 글

Bash 내부 명령어  (0) 2012.10.18
Bash 외부 명령어  (0) 2012.10.18
Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
리눅스에서 이전 폴더로 이동하기  (0) 2012.03.30
Posted by 라판

linux에서 대부분의 모든 시스템 정보는 /proc 내에서 제공된다. 

마찬가지로 cpu에 대한 정보도 /proc 내의 cpuinfo가 가지고 있다. 

cpu 정보를 확인하려면, 

cat /proc/cpuinfo

를 타이핑하면 된다. 

여기서 나오는 정보 중 몇 가지에 대한 설명은 다음과 같다. 

processor- 시스템에서 사용할 수 있는 프로세서의 id 

physical id - 해당 프로세서가 속해 있는 물리적인 cpu의 id 

siblings - 해당 프로세스의 물리적 cpu가 가지고 있는 논리적인 cpu의 갯수

cpu cores - siblings와 유사한 것인듯? 

여기서 실제 물리적인 cpu의 개수를 확인하려면, physical id의 수를 확인하면 된다. 

grep "physical id" /proc/cpuinfo | sort | uniq | wc -l 

마찬가지로 총 가용한 core의 수는 'processor id'의 수를 확인하면 된다. 

grep "processor" /procs/cpuinfo | wc -l 


여기서 사용되는 명령어 중 sort, uniq, wc의 간략한 사용법은 라인 파싱과 관련하여 숙지하는 것이 좋을 듯 하다. 

* wc - 파일의 줄, 단어, 바이트 수 등에 대한 정보 출력 

* sort - 텍스트파일의 라인을 정렬하여 출력 

* uniq - 중복되는 라인은 제거하여 출력 




'리눅스 > 일반' 카테고리의 다른 글

Bash 외부 명령어  (0) 2012.10.18
Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
리눅스에서 이전 폴더로 이동하기  (0) 2012.03.30
find 와 grep를 이용한 파일/문자열/디렉터리 찾기 및 치환  (0) 2012.02.02
Posted by 라판

  • linux command 'screen' - 터미널 에뮬레이션으로 하나의 터미널에서 여러 개의 스크린을 사용할 수 있다. 터미널이 종료되어도 세션은 계속 유지되어, 다른 터미널에서도 해당 세션에 다시 attach할 수 있다.
    • screen 생성 : screen,
    • screen 이동 : screen -X prev[next]
    • screen 종료 : screen -d
    • 현재 창 종료 : screen -X kill
    • screen 목록 확인 : screen -list or -ls
이전처럼 여러 터미널을 띄어가며, 창을 옮겨다니는 수고는 더 이상 안해도 된다. 
아, 정말 리눅스는 무궁무진하구나. 

참고로 첨부파일은 리눅스 screen의 설정파일.(root에 두고 사용) 

'리눅스 > 일반' 카테고리의 다른 글

Redirection  (0) 2012.10.18
cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
리눅스에서 이전 폴더로 이동하기  (0) 2012.03.30
find 와 grep를 이용한 파일/문자열/디렉터리 찾기 및 치환  (0) 2012.02.02
ANSI color  (0) 2011.12.20
Posted by 라판

안드로이드 EventHub를 살펴보다, 초반 device 검색 시, poll 매커니즘을 이용하는 것을 알았다. 

이에 대해 poll 매커니즘에 대한 간단한 설명을 아래 스크랩하엿다. 
이와 더불어 inotify도 사용하는 데 이에 대한 정리도 필요함 

출처 - http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Network_Programing/Documents/Poll

poll을 이용한 입출력 다중화

poll은 select 와 마찬가지로 다중입출력 을 구현하기 위한 방법으로 사용되며, 동시에 여러개의 클라이언트를 다루는 서버를 제작하기 위한방법으로 흔히 사용된다. 

select 의 경우 입출력 이벤트가 발생했을 때 넘겨주는 정보가 너무 적음으로써, 프로그래밍시 여기에 신경을 써줘야 하는데 poll 을 이용하면 이러한 제한을 극복할수 있다.
select 에 대한 자세한 내용은 select 를 통한 입출력 다중화 와 다중연결서버 만들기 (2) 를 참조하기 바란다. 

poll
다음은 poll의 함수원형이다.
int poll(struct poolfd *ufds, unsigned int nfds, int timeout);
poll이 여러개의 파일을 다루는 방법은 select 와 마찬가지로 파일지시자의 이벤트를 기다리다가 이벤트가 발생하면, poll 에서의 block 이 해제되고, 다음 루틴에서 어떤 파일지시자에 이벤트가 발생했는지 검사하는 방식을 사용하게 된다.
우선 poll 함수의 첫번째 인자인 pollfd 구조체에 대해서 알아보도록 하겠다. poolfd 구조체만 알만 poll 의 대부분을 다 이해한것이나 마찬가지이니, 주의 깊게 읽어 바란다.
struct pollfd
{
	int fd;         // 관심있어하는 파일지시자
	short events;   // 발생된 이벤트
	short revents;  // 돌려받은 이벤트
};
pollfd 구조체는 3개의 멤버변수가 있는데, 이 구조체에 우리가 관심있어하는 파일지시자를 세팅하고(fd), 관심있어 하는 파일지시자가 어떤 이벤트가 발생하는걸 기다릴것인지(events)를 지정하게 된다. 그럼 poll 은 해당 fd 에 해당 events 가 발생하는지를 검사하게 되고, 해당 events 가 발생하면 revents 를 채워서 돌려주게 된다. 
revents 는 events 가 발생했을때 커널에서 이 events 에 어떻게 반응 했는지에 대한 반응 값이다.
후에 revent 값을 조사함으로써, 해당 파일지시자에 어떠한 event 가 최해지고 커널에서 그 event를 어떻게 처리했는지 (입력/출력이 제대로 이루어졌는지, 아니면 에러가 발생했는지)를 알아내서 적절한 조취(읽을 데이타가 있으면 읽거나 하는등의 일)를 취할수 있게 된다.

그럼 events 에 세팅할수 있는 events 에 대해서 알아보도록 하겠다. 이 값들은 <sys/poll.h> 에 디파인 되어 있다.
    #define POLLIN      0x0001  // 읽을 데이타가 있다.
    #define POLLPRI     0x0002  // 긴급한 읽을 데이타가 있다.
    #define POLLOUT     0x0004  // 쓰기가 봉쇄(block)가 아니다. 
    #define POLLERR     0x0008  // 에러발생
    #define POLLHUP     0x0010  // 연결이 끊겼음
    #define POLLNVAL    0x0020  // 파일지시자가 열리지 않은것같은
                                // Invalid request (잘못된 요청)
2번째 인자인 nfds 는 pollfd 의 배열의 크기 즉 우리가 조사할 파일지시자의 크기(네트웍프로그래밍측면에서 보자면 받아들일수 있는 클라이언트의 크기) 로, 보통 프로그래밍 할때 그크기를 지정해준다. 
마지막 아규먼트인 timeout 는 select 의 time 와 같은 역할을 한다.
  • 값을 지정하지 않을경우 이벤트가 발생하기 전까지 영원히 기다린다.
  • 0일경우는 기다리지 않고 곧바로 다음 루틴을 진행하고자
  • 0보다 큰 양의 정수일 경우에는 해당 시간만큼을 기다리게 된다. 해당 시간내에 어떤 이벤트가 발생하면 즉시 되돌려 주며, 시간을 초과하게 될경우 0을 return 한다.

위의 3가지 아규먼트를 채워넣음으로써 poll을 사용할수 있다. poll 함수의 return 값은 int 형인데, 에러일경우 -1 이 리턴되고, 그렇지 않을경우 revent 가 발생한 pollfd 구조체의 숫자를 돌려주게 된다. 

이제 poll 버젼의 우편주소 프로그램의 서버를 작성해 보도록 하자. 

예제 : zipcode_poll.c
#include <sys/time.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <sys/poll.h> 

// 받아들일수 있는 클라이언트의 크기
#define OPEN_MAX    600 

int main(int argc, char **argv)
{

    int server_sockfd, client_sockfd, sockfd;

    int i, maxi;
    int nread;
    int state = 0;

    socklen_t clilen;

    struct sockaddr_in clientaddr, serveraddr;

    char buf[255];
    char line[255];

    FILE *fp;

    struct pollfd client[OPEN_MAX];

    if (argc != 2)
    {
        printf("Usage : ./zipcode_poll [port]\n");
        printf("예    : ./zipcode_poll 4444\n");
        exit(0);
    }


    if ((fp = fopen("zipcode.txt", "r")) == NULL)
    {
        perror("file open error : ");
        exit(0);
    }

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket error : ");
        exit(0);
    }
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1]));

    state = bind(server_sockfd, (struct sockaddr *)&serveraddr, 
                sizeof(serveraddr));

    if (state == -1)
    {
        perror("bind error : ");
        exit(0);
    }
    state = listen(server_sockfd, 5);
    if (state == -1)
    {
        perror("listen error : ");
        exit(0);
    }

    // pollfd  구조체에 
    // 소켓지시자를 할당한다.  
    // 소켓에 쓰기 events (POLLIN)에 대해서 
    // 반응하도록 세팅한다. 
    client[0].fd = server_sockfd;
    client[0].events = POLLIN;

    // pollfd 구조체의 모든 fd 를 -1 로 초기화 한다.  
    // fd 가 -1 이면 파일지시자가 세팅되어있지 않다는 뜻이다. 
    for (i = 1; i < OPEN_MAX; i++)
    {
        client[i].fd = -1;
    }
    maxi = 0;

    // POLLING 시작
    for (;;)
    {
        nread = poll(client, maxi + i, 1000);

        // 만약 POLLIN 이벤트에 대해서 
        // 되돌려준 이벤트가(revents) POLLIN
        // 이라면 accept 한다. 
        if (client[0].revents & POLLIN)
        {
            clilen=sizeof(clientaddr);
            client_sockfd = accept(server_sockfd, 
                            (struct sockaddr *)&clientaddr, 
                            &clilen);
            for (i = 1; i < OPEN_MAX; i++)
            {
                if (client[i].fd < 0)
                {
                    client[i].fd = client_sockfd;
                    break;
                }
            }

            if (i == OPEN_MAX)
            {
                perror("too many clients : ");
                exit(0);
            }

            client[i].events = POLLIN;

            if (i > maxi)
            {
                maxi = i;
            }

            if (--nread <= 0)
                continue;
        }

        // 현재 파일지시자의 총갯수 만큼 루프를 돌면서 
        // 각 파일지시자에 POLLIN revent 가 발생했는지를 조사하고 
        // POLLIN이 발생했다면, 해당 파일지시자에서 데이타를 읽어들이고, 
        // 주소정보를 돌려준다. 
        // 만약 "quit" 를 읽었다면, 소켓연결을 끊는다. 
        for (i = 1; i <= maxi; i++)
        {
            if ((sockfd = client[i].fd) < 0)
                continue;
            if (client[i].revents & (POLLIN | POLLERR))
            {
                rewind(fp);
                memset(buf, 0x00, 255);
                if (read(sockfd, buf, 255) <= 0)
                {
                    close(client[i].fd);
                    client[i].fd = -1;
                }
                else
                {
                    if (strncmp(buf, "quit", 4) == 0)
                    {
                        write(sockfd, "byebye\n", 7);
                        close(client[i].fd);
                        client[i].fd = -1;
                        break;
                    }
                    while(fgets(line, 255, fp) != NULL)
                    {
                        if (strstr(line, buf) != NULL)
                            write(sockfd, line, 255);
                        memset(line, 0x00, 255);
                    }
                }
            }
        }
    }
}
select 버젼인 다중연결서버 만들기(2)와 비교해서 보기 바란다. 
코딩 분위기가 select 와 매우 비슷하다는걸 알수 있을것이다. 

pollfd 에 입력된 파일지시자의 event 에 입력event 가 발생하면, 커널은 입력event 에 대한 결과를 되돌려줄것이다. 
이결과는 입력 event 가 제대로 처리되었다면 POLLIN 을 되돌려줄것이고, 어딘가에서 에러가 발생했다면 POLLERR 을 되돌려주게 될것이다. 
그러므로 우리는 revent 를 검사함으로써, 해당 파일지시자에 읽을 데이타가 있다는걸 알게 되고, 데이타를 읽어서 적당한 행동(여기에서는 주소를 돌려주는)을 할수 있다. 
위의 프로그램은 이러한 일련의 과정을 보여준다.
select 버젼과 별차이가 없으므로 select 버젼의 쏘쓰를 이해했다면 위의 쏘쓰를 이해하는데 별 어려움이 없을것이다. 

poll 은 보통 select 에 비해서 해당파일지시자에 대해서 보다 많은 정보를 되돌려줌으로, 보통 select 보다 선호되는 추세이다.
select 버젼과 마찬가지로 polling 중간에 파일 I/O 가 들어갈경우, 파일 I/O 작업에서의 block 때문에 짧은시간에 다수의 메시지를 처리할경우 문제가 될 소지가 있다. 
그러므로 되도록이면 polling 중간에 파일 I/O 가 일어나지 않도록 해주어야 한다.
위의 쏘쓰의 경우도 주소정보를 미리 메모리 상에 올려놓고 쓰는게 더욱 좋은 방법이 될것이다.

Posted by 라판

리눅스에서 작업을 하다 보면, 폴더를 옮겨가며 작업을 하는 데, 깊은 깊이의 폴더로 갔다가 상위 폴더로 

가려면 여러번의 폴더 이동을 하곤 했다. 그런데 cd - 명령은 바로 이전에 있었던 폴더로 바로 가게 해주어

편리하다. 커널에서 각 드라이버 폴더로 가서 작업 하다, 다시 돌아올 때 유용. 

 


http://www.lug.or.kr/home/bbs/board.php?bo_table=centos_book&wr_id=64&page=6#bbs


아마도 모르시는분들이 있을것 같아 이곳에 적어둡니다.

쉘작업하면서 이전 디렉토리로 가야할 경우가 간혹 있습니다.

이때에는 cd - 라고 입력하시면 됩니다.

[root@lug ~]# cd /usr/local/src
[root@lug src]# pwd
/usr/local/src
[root@lug src]# cd -
/root
[root@lug ~]# pwd
/root
[root@lug ~]#

간단하죠..

'리눅스 > 일반' 카테고리의 다른 글

cpu 갯수 확인하기  (0) 2012.10.16
screen 명령어  (0) 2012.10.16
리눅스에서 이전 폴더로 이동하기  (0) 2012.03.30
find 와 grep를 이용한 파일/문자열/디렉터리 찾기 및 치환  (0) 2012.02.02
ANSI color  (0) 2011.12.20
cron 사용법  (0) 2011.12.19
Posted by 라판