CHIP_COUNT=`cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l`; CHIP_CORES=`cat /proc/cpuinfo | grep "siblings" | tail -1 | cut -d: -f2`; echo "CPU: $CHIP_COUNT chips x $CHIP_CORES cores"

출처 : http://kukuta.tistory.com/35


Read/Write Lock(이하 rwlock)의 기본적인 생각은 아래와 같이 간단하다.

  * Read 작업은 값을 변경하지 않으니 몇개가 붙어도 동기화에 문제가 생기지 않는다.
  * Write 작업은 값을 변경 할 수도 있으니, 하나의 크리티컬 섹션에 하나만 붙어야 한다.
  * Read 작업은 끼리는 여러개가 하나의 크리티컬 섹션에 접근 가능하나, Read하는 것을 도중에 바꾸면 안된다.

 

 위의 세 가지 사항 정도만 제외 한다면 rwlock은 mutex랑 비슷하다. 개념도 비슷하고, 사용법도 비슷하고, 하는
일도 비슷하다.

 rwlock의 장점은 read 작업에 있어서 여러개의 쓰레드가 서로 블록킹 하는 일이 없어 괜한 오버헤드를 가지고 오
지 않고, 단점은
그 특성상 read작업이 많다면 거기에 눌려 write 오퍼레이션은 뒤로 밀리기 마련이다.
 
 write lock을 걸려고 하는 쓰레드가 자원을 못 받아 말라 죽는
시나리오를 만들어 보자.

 1) 1번 쓰레드가 A라는 공유 자원을 참조 하려고 한다.
   *
아직 아무런 lock이 걸려 있지 않으므로 커널은 lock을 허락한다.
 2) 2번 쓰레드가 A라는 공유 자원을 변경 하려고 한다.
   * 변경이라는 것은 wrtie lock을 걸어야 하는데 아직 read 작업이 있으므로 write를 잠시 멈춘다.
     
하지만 그 사이에 다른 read 작업이 또 들어 온다. read 작업은 공유가 되므로 커널은 뒤 늦게 온 read 작업을
     크리티컬섹션 안으로 넣어 버린다. 이런 현상의 반복으로 write를 요청하는 thread는 굶어 죽는 경우가 발생
     해 버릴수 있다.(현실적으로는 이런 경우를 대비하여 만들었 겠지만, 그래도 rwlockmodify작업보
    다는 read가 더 많은 곳에 사용하는 것이 가장  이상적이다
.)


#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict    rwlock, const pthread_rwlockattr_t    *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);


 API가 상당히 직관적이다. mutex같은 것들과 마찬가지로 pthread_rwlock_t 객체를 사용하기 이전에
pthread_rwlock_init으로 객체르르 초기화 해주고, 사용이 끝나고 커널에 반환 해야 할 경우에는 pthread_rwlock_destroy로 객체를 해제해 준다.

 read 작업을 하는 경우에는 pthread_rwlock_rdlock을 호출 하고, write작업을 할경우에는
pthread_rwlock_wrlock을 호출 하면 된다. 그리고 어떠한 read 작업이든, write작업이든 lock을 풀어 줄때는
pthread_rwlock_unlock을 호출 한다. read작업을 다른 말로 shared 작업, 즉 공유가 가능한 작업이라고 하는데 구현상 그 갯수에 제한을 두고 있다.
 
 
Single Unix
계열에서는 아래와 같은 함수를 지원한다..

#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

  try라는 이름과 같이 단시 시도를 할 뿐이다. 만일 lock을 잡을 수 없는 상황이라면 바로 리턴을 한다. 리턴 값은
lock를 잡을 경우에는 0을 리턴하고, 그렇지 못하다면 EBUSY를 리턴한다.

 아래의 예제 코드는 두개의 read lock과 하나의 write lock을 사용한다. 하나의 read lock을 걸고 다른 read lock
를 걸었을 경우 과연 예상대로 lock이 잡히는지 안잡히는지, 그리고 read lock가 걸려 있는 상태에서 write lock는 과연 대기 상태에 있는지를 알아 보고자 하는 코드다.

예제 코드 닫기

#include <pthread.h>
#include <iostream>
#include <unistd.h>

pthread_rwlock_t g_rwLock;
int g_share = 0;

void* thr_readLock(void* arg) {
 int ret = pthread_rwlock_rdlock(&g_rwLock);
 if(ret == 0) {
  std::cout << "try to read lock successfully complete!!" << std::endl;
 }
 sleep(3);
 pthread_rwlock_unlock(&g_rwLock);
 std::cout << "unlock the read lock" << std::endl;
}

void* thr_writeLock(void* arg) {
 int ret = pthread_rwlock_wrlock(&g_rwLock);
 if(ret == 0) {
  std::cout << "try to write lock successfully complete!!" << std::endl;
 }
 pthread_rwlock_unlock(&g_rwLock);
 std::cout << "unlock the write lock" << std::endl;
}

int main() {
 int ret = 0;
 ret = pthread_rwlock_init(&g_rwLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 
 pthread_t readThr[2];
 pthread_t writeThr;

 ret = pthread_create(&readThr[0], NULL, thr_readLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 ret = pthread_create(&readThr[1], NULL, thr_readLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 ret = pthread_create(&writeThr, NULL, thr_writeLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 
 sleep(10);
 pthread_rwlock_destroy(&g_rwLock);
}

주석문
'#'로 시작하는 줄.
줄의 중간에 '#'이 와도 주석으로 인식하지만 다음과 같이 이상하게 동작하는
경우가 발생한다. >
코드:

    #!/bin/sh
    AA=abcd     # 여기는 주석.
    BB=${AA}kkk
    echo ${BB}

실제 원하는 출력은 "abcdkkk"이지만 실제 출력은 "abcd kkk"가 되어 버린다.
즉, abcd뒤쪽의 공백문자가 포함되어 버린다.
따라서 줄의 중간에 '#'을 넣어서 주석을 만들지는 말것.
실제 test를 해보니까 그렇지 않는 것 같다(bash-2.05b).


Shell Script 실행하기
코드:

    1. $ source sample
    2. $ . sample
    3. $ bash sample
    4. $ chmod +rx sample;./sample  // #!/bin/bash 포함.
        모드를 변경할때 rx를 주어야 한다. shell scripts는 shell에서 읽어서
        수행해야 하므로 read 속성이 주어져야만 한다.

위에서 1, 2번 그리고 3,4번은 실행이 다르다. 1,2번은 기존에 존재하던 shell에서
스크립트를 수행하고 3,4번은 새로운 셀을 생성해서 실행하게 된다. 이 경우에
문제가 되는것은 스크립트 내부에서 "exit 0"과 같은 명령을 사용하면 1, 2번의
경우는 현재 shell이 닫혀버린다.

그리고 또하나의 문제는 1,2번의 경우는 현재 shell에서 이어져서 수행되므로
스크립트 내부에서 사용한 변수나 함수들이 그대로 남아있다. 하지만 3,4번의
경우는 현재 셀의 서브셀로 수행되므로 스크립트가 종료된후에는 스크립트내부의
변수나 함수는 현재 셀에서 유효하지 않게 된다.

따라서 수행하는 스크립트의 변수나 함수를 현재 셀에서도 유효하게 할때는
". sample" 나 "source sample"를 사용하고 그냥 스크립트를 수행하고 종료시킬때는
"bash sample" 나 "./sample"를 사용



매직넘버
리눅스에서는 기본 셀인 배쉬이외에도 다양한 종류의 셀을 사용할 수 있다.
따라서 배쉬용 셀스크립트가 씨셀에서 실행된다면 오류가 발생할 수 있다.
따라서 스크립트 파일의 처음 행에 파일을 실행시키는데 사용할 셀의 절대
경로를 아래와 같이 표시하게 된다.
코드:

    #!/bin/bash

이 매직넘버는 수행을 의미하므로 다음과 같이 사용할 수도 있다. 다음은 자기
자신을 출력하는 shell script이다.
코드:

    #!/bin/cat

이 파일은 스스로를 출력하는 셀스크립트이다.



셀스크립트 확인하기
코드:

    $ file sample

결과는 ASCII가 아니라 C 스크립트 파일로 나타난다.



변수의 사용
$A A라는 변수
이렇게 사용하는 것은 지양하도록 한다. 만약 A라는 변수가 정의되지
않았을때 완전히 공백이 되어 버리기 때문에 다음과 같은 경우에
에러가 발생한다.
코드:

            if [ $A = '1' ];then
                echo "A is 1"
            fi


${A} A라는 변수
"$A" A라는 변수
'$A' '$A'라는 스트링
\$A '$A'라는 스트링
`$A` A라는 변수명의 명령의 실행.
`AA` AA라는 명령의 수행.(이식성이 강한 오래된 관습)

다음과 같이 사용할 경우
코드:

                AA=`AA`
                BB=$(AA)kkk
            


BB는 다음과 같이 확장된다.
코드:

                BB=`AA`kkk
            


따라서 다음과 같이 사용하는 방법을 고려해 볼 것.
코드:

                AA=$(shell AA)
                BB=$(AA)kkk
            


AA는 명령이 수행된후 곧바로 확장되게 된다.

$(AA) AA라는 명령의 수행.

$(shell AA) AA라는 명령의 수행.


변수에 값을 대입하기
코드:

    <case1> AA = "3333"     (X)
    <case2> BB="3333"       (O)

<case1>과 <case2>는 차이가 없어 보이지만 엄청난 차이가 존재한다. shell은 위
명령을 수행하면서 <case1>의 경우는 'AA'라는 명령을 수행하면서 그 파라메터로
'='와 "3333"을 대입하는 것으로 처리한다. 따라서 결과는 'AA'라는 명령이 없다고
출력된다.
<case2>의 경우는 shell이 'BB'라는 변수에 "3333"을 대입하는 것으로 정확하게
인식한다. 따라서 <case2>의 경우가 정확한 표현이다. 즉 '='의 양쪽을 띄어쓰지
않는다.


변수의 확장의 방지
코드:

    #!/bin/sh
    #출력이 0_tmp, 1_tmp라고나오길 기대하지만 shell은 i_tmp라는 변수가
    #존재하지 않으므로 공백을 출력하게 된다.
    for i in 0 1 2
    do
        echo $i_tmp
    done

    #정상적으로 된 경우. 변수를 확장하지 않으므로 0_tmp, 1_tmp, 2_tmp가 출력.
    for i in 0 1 2
    do
        echo ${i}_tmp
    done

    #두번째 방법
    for i in 0 1 2
    do
        echo $i{_tmp}
    done



조건 제어구문
코드:

    if, case, while, for, until

    if test     조건
    then        명령어
    fi

    if test; then
    fi

    if test     조건
    then        명령어
    else        조건을 만족하지 않았을때 실행할 명령어
    fi

    if test     조건
    then        명령
    elif test   조건
    then        명령
    else        명령
    fi

    다음과 같은 에러메세지가 발생하는 이유는 다음과 같다.
        [: =: unary operator expected
    비교하는 파라메터를 ""로 감싸주지 않았을 때 만약 파라메터가 NULL
    String이라면 다음과 같이 취금되어 버린다.
        if [ = "yes" ]
    따라서 파라메터는 무조건 다음과 같이 ""로 감싸서 처리해주어야 한다.
        if [ "$timeofday" = "yes" ]
        if [ "" = "yes" ]



조건의 Test
test or []
[]를 사용할때는 '['와 ']'와 조건사이에 빈칸을 삽입해야만 한다.



true와 false
셀스크립트의 조건문에서 참은 0을, 거짓은 0이 아닌값을 의미한다.

코드:

    # true
    # echo $?
    0

    # false
    # echo $?
    1

    if true; then
    fi

    if faluse; then
    fi


조건문의 논리를 단순화하기 위해 true를 대신하는 별칭으로 ':'를 종종
사용한다.

코드:

    if :;then
    fi



함수의 실행결과(반환값)을 조건문에 대입하기
잘못된 예1 >
코드:

    exe_command
    if [ $? ]; then
        # 0이 아닌 어떤 반환값에 대해서도 들어올 것 같은데
        # 실제로는 모든 반환값에 대해서 이곳으로 들어온다. 따라서 잘못된
        # 예제이다.
        echo return value is true.
    fi


잘못된 예2 >
코드:

    RET=`exe_command`
    if [ RET = 0 ];then
        # RET에는 exe_command의 반환값이 아니라 stdout 출력값이 들어가게 된다.
        # 따라서 위 문장은 정확한 표현이 아니다.
        echo return value is true
    fi


맞는 예1 >
코드:

    exe_command
    if [ $? -eq 0 ]; then
        echo return value is true.
    fi


맞는 예2 >
코드:

    if exe_command; then
        echo return value is true.
    fi


맞는 예3 >
코드:

    exe_command
    case $? in
        0)
            echo "return zero";;
        1)
            echo "return one";;
        *)
            echo "unknown return value";;
    esac



if문
코드:

    if [ -f ~/.bashrc ]; then
        . ~/.bashrc
    fi

    if [ -f ~/.bashrc ]
    then
        . ~/.bashrc
    fi


테스트 조건 파일 옵션

    -b 디스크 드라이브와 같은 Block형 장치
    -c 터미널, 프린터, 네트워크같이 Character형 장치
    -d 디렉토리
    -e 존재한다.(이식적이지 않으므로 -f를 사용한다.)
    -f 일반파일
    -k 스티키비트가 설정됨
    -p 네임드 파이프의 형태
    -r 읽기 권한이 허가된 상태
    -s 사이즈가 0이 아님
    -w 쓰기 권한이 허가된 상태
    -x 실행 권한이 허가된 상태
    -L 심벌릭 링크의 형태
    -S 소켓의 형태

만약 위 조건의 NOT일때는 "[ ! -f abcd.txt ]"가 된다.~


논리 연산 옵션

    -a 논리적 AND
    -o 논리적 OR
    ! 논리적 NOT


정수 비교 옵션

    -eq Equal(=)
    -ge Greater then or Equal to(>=)
    -gt Greater then(>)
    -le Less then or Equal to(<=)
    -lt Less then(<)
    -ne Not Equal(!=)


문자열 비교 옵션

    -n 문자열의 길이가 0이 아니다.
    -z 문자열의 길이가 0이다.
    = 두 문자열이 같다.
    주의할점은 "=="와 혼동하지 말것.
    != 두 문자열이 같지 않다.


문자열 비교시 주의할 점.
"[ $S1 = $S2 ]"와 같이 사용하면 $S1이나 $S2가 비어있다면 에러가
발생한다. 따라서 다음과 같은 방법을 사용한다.
"[ x$S1 = x$S2 ]" 혹은 [ "$S1"="$S2" ]


while 문
while 조건에 준하는 명령
do 실행할 명령어
done


case 선택 제어문
코드:

    #!/bin/sh
    case "$FLAG" in
        +)  exit;;                                  --> '+'이면 종료.
        [aeiou] ) echo -e "you inputvowel\n" ;;     --> aeiou이면 출력.
        *) echo -e "you input consonant\n" ;;       --> 그이외.
    esac


코드:

    #!/bin/sh
    echo "Is it morning? Please answer yes or no"
    read timeofday
    case "$timeofday" in
        yes | y | Yes | YES )
            echo "Good Morning";;
        n* | N* | [nN][oO])
            echo "Good Afternoon";;
        *)
            echo "Sorry, answer not recognized";;
    esac


for 반복 제어문
코드:

    for TEMP in A B C D
    do
        echo $TEMP
    done


코드:

    # /etc/passwd의 각 행에 대해서 수행.
    for LINE in `cat /etc/passwd`
    do
        echo $LINE >> backup
        echo $LINE
    done


for문에 유용한 seq 명령어
코드:

    # seq 1 3
    1
    2
    3


코드:

    #!/bin/sh
    for temp in `seq 1 3`; do
        echo $temp
    done



until 반복제어문
명령을 먼저 실행한 후에 조건을 검사한다.

코드:

    until [ "`who | grep jarrett`"]
    do
        echo "hacker is NOT logged in"
        sleep 1
    done
    echo -e "Notorious Hacker jarrett appeared at \a" `date`



and 리스트
코드:

    statements1 && statements2 && statements3 && statements4
    if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo "there"
    then
        echo "all is true"
    else
        echo "there is one false"
    fi



or 리스트
코드:

    statement1 || statement2 || statement3 || statement4

    if [ -f file_one ] || echo "hello" || echo "there"
    then
        echo "there is true more one.
    else
        echo "all is false"
    fi



문장블럭
코드:

    get_confirm && {
        grep -v "$cdcatnum" $tracks_file > $temp_file
        cat $temp_file > $tracks_file
        echo 
        add_record_tracks
    }



쉘스크립트와 함수
쉘스크립를 명령어 라인에서 직접 실행하면 서브셀이라 불리는 셀의 복사가
기동되어 스크립트안의 처리는 서브셀에서 한다. 서브셀과 원래 셀의 현재
디렉토리는 독립되어 있으므로 스크립트안에서 아무리 �p 디렉토리를 변경해도 원래
쉘의 디렉토리에는 영향을 주지 않는다. 한편, 함수의 경우는 원래 쉘에서 그대로
실행되므로 현재 디렉토리의 변경에 효과적이다.
("source"나 "."로 쉘스크립트를 실행하면 현재 쉘에서 수행된다.)
방법 : 함수를 저장하고 있는 파일을 ". func.txt"라고 실행시키면 함수가 현재
쉘에 등록된다.


함수의 사용
함수를 사용할 때 주의 사항은 함수명과 뒤쪽의 '{'사이에는 반드시 공백이
존재해야 한다.
function이라는 단어는 생략이 가능하다.
코드:

    #!/bin/sh
    # function foo() {...
    function foo(){
        echo "Function foo is executing"
    }

    echo "ScriptStarting"
    foo
    echo "Script Ended"
    exit 0


    # function foo() {...
    foo() { echo JAY;}
    result=$(foo)



함수에서 인자를 받기
코드:

    #!/bin/sh

    function quit() {
        exit
    }

    function e() {
        echo $1
    }
    e Hello
    e World
    quit



함수의 반환값 이용하기
1. 숫자값을 반환하기.
코드:

    function func() {
        return 0
    }
    
    result=$(func)


2. 문자 스트링을 반환하기
코드:

    function func() {
        echo kkk
    }

    result=$(func)


: 명령
코드:

    while :     -> 무한 루프( while true와 동일하다)
    null 명령
        if 조건 ;then
            :
        else
            명령
        fi


local 키워드
함수내부의 지역 변수를 선언할때 사용.
local var="aldfjas"

코드:
    
    #!/bin/sh
    sample_text="global variable"
    foo(){
        local sample_text="local variable"
        echo "Function foo is executing"
        echo $sample_text
    }

    echo "script starting"
    echo $sample_text

    foo



eval
인수를 평가하게 해준다.

    foo=10 --> foo <- 10
    x=foo --> x <- foo
    y='$'$x --> y <- $foo
    echo $y --> $foo가 출력

    foo=10 --> foo <- 10
    x=foo --> x <- foo
    eval y='$'$x --> y <- $foo
    echo $y --> $foo인 10이 출력


exec
현재 셀을 다른 프로그램으로 대체한다.

    exec echo "asljfasldfkasdlf" --> exec 아래의 명령은 실행되지 않는다.



exit n
스크립트의 반환값을 지정한다. 만약 종료상태를 지정하지 않고 종료한다면
마지막에 실행된 명령의 반환값으로 사용될 것이다.

    반환값 0 : 성공
    1 ~ 125 : 스크립트에 의해 사용될 수 있는 값.
    126 : 파일이 실행 가능하지 않다.
    127 : 명령이 발견되지 않았다.
    128이상 : 시그널이 발생했다.


printf
최신 셀에서만 유효하다.
코드:
    
    printf "format string" paramerter1 parameter2
    printf "%s\n" hello
    printf "%s %d\t%s" "Hi There" 15 Peopel



    \\ : 백슬래쉬
    \a : 경고
    \b : 백스페이스
    \f : 폼피드
    \n : 새줄
    \r : 개행
    \t : 수평탭문자
    \v : 수직탭문자
    \000 : 8진수 값을 가지는 한 문자


set 명령
set 명령은 쉘을 위한 파마메터 변수를 설정한다. 이것은 빈칸으로 구분되는
값을 출력하는 명령에서 필드를 사용하는 유용한 방법이 될 수 있다.

코드:

    # date의 출력결과가 "2003. 06. 22. (일) 19:54:41 KST"일때.

    set $(date)



    # $0 -> date 명령을 지시하지 않고 현재 쉘스크립트의 이름을 지시한다.
    # $1 -> "2003."
    # $2 -> "06."
    # $3 -> "22."
    # $4 -> "(일)"
    # $5 -> "19:59:06"
    # $6 -> "KST"


shift
$2 -> $1
$3 -> $2


trap
시그널(signal)을 받아들일 때 수행하는 동작을 지정하는 데 사용된다.
[list]
trap `rm -f /tmp/my_tmp_file_$$` INT
--> INT(CTRL+C)가 발생하면 수행하는 명령.
trap - INT --> trap해제.
[list]

명령의 수행

    `명령` : 이식성이 강한 오래된 관습.
    $(명령) :



산술 확장

echo $((1+1)
echo $(( 1 + 1 ))
echo $[1+1]
echo $[ 1 + 1 ]
echo `echo 1+1 | bc -l`
코드:

    $(())

    #!/bin/sh
    # 주의할 점은 "x = $(($x+1)"이라고 '=' 양쪽을 띄어쓰지 않는다.
    x=0
    while [ "$x" -ne 10 ]; do
        echo $x
        x=$(($x+1))
    done


    #!/bin/sh
    x=0
    while [ "$x" -ne 10 ]; do
        echo $x
        let x = $x + 1
    done


    #!/bin/sh
    x=0
    while [ "$x" -ne 10 ]; do
        echo $x
        let x-=1
    done


    #!/bin/sh
    i=0
    while [ "$i" -ne 10 ]; do
        filename=`printf %06d.jpeg "$i"`
        echo "$filename"
        sleep 1
    done]


toggle 상태 만들기.
코드:

    val=0
    while true; do
        echo $val
        # 주의할 점은 '=' 양쪽에 공백이 들어가서는 안된다.
        val=$(( 1 - $val))
        # 혹은 "let val= 1 - $val"
        sleep 1
    done



파라미터 변수
[list]
$1,$2,... 스크립트에 주어진 파라미터
"$9"보다 큰 매개변수는 "${10}"와 같이 "{}"로 감싸주어야 한다.

$* 환경변수 IFS의 첫문자로 구분되고, 하나의 변수에 저장되는 모든
파라미터의 목록, 만약 IFS가 NULL이면 모든 파라메터가 붙어서
나온다.

$@ IFS 환경변수를 사용하지 않는 $*에 대한 변형
"$*"와 "$@"중에서 "$@"를 사용하는 것을 권장한다.

echo `basename $0`
실행된 스크립트에 "./"가 붙어있는 경우에 떼어내고, 스크립트
이름만을 출력한다.
[list]

파라메터 확장

    ${param:-default}
    param이 널이 아니면 param을 반환하고 널(혹은 존재하지 않으면)이면
    default의 값을 반환한다. 이 경우에도 param의 값은 변하지 않는다.
    ${param:=bar}
    만약 param이 널이 아니면 param을 반환하고 널이면 param에 bar를 넣고
    param을 반환한다. 이 경우에 param의 값이 bar로 변경된다.
    ${param:+bar}
    param이 존재하고 널이 아니면 bar의 값으로 설정하고 널이면 널을 반환한다.
    어떤 경우에도 param값은 변경되지 않는다. ${param:-default}와 반대로
    동작한다.
    ${#param}
    param의 길이를 제공한다.
    ${param#word}
    앞에서부터 가장 먼저 word가 일치하는 부분까지를 제거한 나머지 부분을
    반환한다.
    ${param##word}
    앞에서부터 가장 나중에 word가 일치하는 부분까지를 제거한 나머지 부분을
    반환한다.
    ${param%word}
    끝에서부터 가장 먼저 word가 일치하는 부분까지를 제거한 나머지 부분을
    반환한다.
    ${param%%word}
    끝에서부터 가장 나중에 word가 일치하는 부분까지를 제거한 나머지 부분을
    반환한다.
    ${param:?bar}
    param이 널이 아니면 param을 반환하고 param이 널이면 "param: bar"를
    출력하고 현재 셀이 종료된다. 만약 기존의 셀에서 서브셀로 수행된
    스크립트라면 현재 셀이 종료되고 그렇지 않고 기존의 셀에서 이어져서
    수행되었다면 "param: bar"를 출력하고 계속 수행한다.


예제.
코드:
    
        #!/bin/bash

        unset foo
        echo ${foo:-bar}

        foo=fud
        echo ${foo:-bar}

        foo=/usr/bin/X11/startx
        echo ${foo#*/}          // *는 0이상의 어떤 문자를 의미한다.
        echo ${foo##*/}

        bar=/usr/local/etc/local/networks
        echo ${bar%local*}
        echo ${bar%%local*}

    출력
        bar
        fud
        usr/bin/X11/startx
        startx
        /usr/local/etc/
        /usr/



shell script에서 2진수 계산하기
코드:

    # 128과 180의 OR값 구하기
    let 'result = 128 & 180'
    echo $result

    # bc로 리다이렉션해서 x180을 2진수로 변환한 결과를 출력한다.
    # ibase : 입력의 진수(2|8|10|A)
    # obase : 출력의 진수(2|8|10|A)
    echo 'ibase=A;obase=2;180'|bc



Here Document
코드:

    cat << !FUNKY!      --> Here document로 cat에 전달한다.
    hello
    this is a here
    document
    !FUNKY!             --> Here document끝.


>>>> 동작은 cat으로 "!FUNKY!"사이의 글자를 전달하는 역할을 한다.


ed a_test_file << !FunkyStuff! --> ed editor Here document로 입력한다.
3
d
.,\$s/is/was/
w
q
!FunkyStuff! --> here document끝.



Scrip 디버깅
코드:

    sh -n <script>      set -o noexec       형식에러만을 확인한다.
                        set -n              명령을 실행하지 않는다.
    sh -v <script>      set -o verbose      실행하기 전에 명령을 출력한다.
                        set -v
    sh -x <script>      set -o xtrace       명령라인에서 처리한 후에 명령을
                        set -x              출력한다
                        set -o nounset      정의되지 않은 변수가 사용될
                        set -u              때 에러 메시지를 제공한다.



조건 제어관련 셀명령

    break for, until, while 루프를 빠져 나온다.
    continue 루프를 계속 진행.
    echo 표준 출력(1)으로 입력된 내용을 출력.
    exec 현재의 셀을 이용해서 명령어를 실행시킨다.
    exit 현재의 셀을 종료한다.
    let 산술연산과 논리연산을 수행한다.
    read 표준 입력(0)을 통해서 입력을 받는다.
    return 함수를 종료한다.
    test [] 조건을 검사한다.
    `명령어` 명령어를 실행하고 그 결과를 대입한다.


exit와 return
exit는 현재 쉘스크립트를 종료하는 역할을 하고 return은 함수나 sourced
script(?)에서만 반환하는 경우에 사용한다.


배열의 사용
bash의 새 버전부터는 1차원 배열을 지원한다. variable[xx]처럼 선언할 수도 있고
'declare -a variable'처럼 직접적으로 지정해 줄 수도 있다. 배열 선언을
역참조하려면(내용을 알아내려면) ${variable[xx]}처럼 중괄호 표기법을 사용하면
된다.


재지향
파일 디스크립터

    0 : 표준 입력
    1 : 표준 출력
    2 : 표준 에러


코드:

    cat 2>&1    # 표준 에러를 표준출력으로 같이 보낸다.

    make 1>a.a 2>&1
        make의 결과를 a.a로 그리고 error 출력도 a.a로 보낸다.
    



C style의 문자열의 해석
코드:

    # echo '111\n222\n333\n'
    111\n222\n333\n

코드:

    # echo $'111\n222\n333\n'
    111
    222
    333

위 예제에서 볼 수 있듯이 $"" 안에 들어간 문자열은 C의 문자열에서와 같이
\t,\n,\r등이 해석된다.
따라서 다음과 같이 사용할 수 있다.
코드:

    # find . -type f -exec vi -c $'20,30d\nwq\n' \{} \;

파일에 대해서 20~30행을 제거하는 명령이다.


예약된 종료코드

    0
    정상종료.

    1
    광범위한 일반적 에러
    let "var1 = 1/0"
    "divide by zero"같은 잡다한 에러

    2
    bash 문서에 명시되어 있는 쉘 내장명령어의 오사용
    거의 보기 힘들고 보통은 디폴트로 1번 종료 코드로 나타남

    126
    실행 불가능한 명령어의 구동
    퍼미션 문제거나 실행 허가가 없는 명령어

    127
    "command not found"
    $PATH 문제거나 오타일 가능성 있음

    128
    exit에 잘못된 인자 넘김
    exit 3.14159
    exit는 0에서 255사이의 정수만 받음

    128+n
    치명적 에러 시그널 "n"
    kill -9 스크립트의 $PPID
    $?는 137 (128 + 9)을 리턴

    130
    스크립트가 Control-C에 의해 종료됨
    Control-C 는 치명적 에러 시그널 2번(130 = 128 + 2, 바로 위 참고)

    255
    종료 상태 범위 초과
    exit -1
    exit는 0에서 255사이의 정수만 받음


저자가 제안하는 방법은 사용자 정의 종료 코드를 64 - 113(성공시 0도
포함)으로 제한해서 C/C++ 표준을 따르는 것입니다. 이렇게 해도 사용자는
여전히 50개의 코드를 쓸 수 있는 있기 때문에 나중에 스크립트의 문제를 좀 더
깔끔하게 해결할 수 있습니다.


지역화(Localization)
지역화된 쉘스크립트는 시스템의 로케일에 따라 정의된 언어로 텍스트를
출력하게 해준다.

코드:

    #!/bin/bash
    # localized.sh
    E_CDERROR=65
    error()
    {
      printf "$@" >&2
      exit $E_CDERROR
    }
    cd $var || error $"Can't cd to %s." "$var"  #문자열들을 $""로 묶어준다.
    read -p $"Enter the value: " var


    bash$ bash -D localized.sh
    "Can't cd to %s."
     "Enter the value: "
    # -D옵션은 스크립트를 수행하지 않고 $뒤에서 큰따옴표로 묶인 문자열을
    # 보여준다.


    bash$ bash --dump-po-strings localized.sh
    #: a:6
    msgid "Can't cd to %s."
    msgstr ""
    #: a:7
    msgid "Enter the value: "
    msgstr ""
    # --dump-po-strings 옵션은 -D와 닮았지만 gettext의 "po" 포맷을 사용한다.


    # ko.po 파일 내용.
    #: a:6
    msgid "Can't cd to %s."
    msgstr "%s 디렉토리로 옮겨갈 수 없습니다."
    #: a:7
    msgid "Enter the value: "
    msgstr "값을 넣으세요: "
 

    # msgfmt실행.
    bash$msgfmt -o localized.sh.mo ko.po


    # localized.sh.mo 파일을 /usr/local/share/locale/ko/LC_MESSAGES 디렉토리에
    # copy.


    # 이제 스크립트에 첫부분에 다음의 두줄을 추가.
    # TEXTDOMAIN과 TEXTDOMAINDIR 변수는 전체 환경으로 export되어야 한다.
    TEXTDOMAINDIR=/usr/local/share/locale
    TEXTDOMAIN=localized.sh



error string
: bad interpriter
이 에러는 쉘스크립트파일이 UNIX형식이 아닌 DOS 형식일때 이러한 에러가
발생한다. 주의할 것.


생각해 볼 문제
코드:

    test -d package || ( echo 'Wrong working directory.'; exit 1 )
    [ -d package ] || ( echo 'Wrong working directory.'; exit 1 )

위 문장이 어떻게 동작할 것인가. 단순하게 생각할때는 package라는 디렉토리가
존재한다면 문장이 출력되지 않을 것이다. 그리고 package라는 디렉토리가 존재하지
않는다면 문장을 출력하고 스크립트를 종료하게 될 것이다. 하지만 문장을 출력하고
종료되지 않는다. '('와 ')'로 묶인곳이 실행되면서 현재 shell이 새롭게 하나
생성되어서 실행된다. 따라서 exit를 수행할때는 새롭게 생성된 shell이 종료되고
현재 shell은 종료되지 않는다. 따라서 exit로 종료되지 않고 계속 수행되게 된다.

따라서 다음과 같이 수정한다.
코드:

    # if문 대체하기.
    if [ -d package ];then
        echo 'Wrong working directory.'
        exit 1
    fi

    # 문장 블럭 사용하기.
    # 주의할 점은 'exit 1' 다음에 ';'가 들어가 주어야 한다.
    [ -d package ] || { echo 'Wrong working directory.'; exit 1; }

    # 그냥 '('')'를 없애기
    # '||'와 ';'중에 '||'가 우선순위가 더 높아서 의도한 대로 수행된다.
    # 하지만 블럭의 구분이 모호해진다. 따라서 문장 블럭을 사용하는것이 좋을 것
    # 같다.
    [ -d package ] || echo 'Wrong working directory.'; exit 1


임시파일의 생성

    $$ : 임의의 난수를 발생한다.
    이 숫자값은 현재 shell에서는 계속동일한 값을 가진다.

코드:

    #!/bin/sh

    echo "temp file" > temp_$$
    rm -f temp_$$




(원글: http://cafe.naver.com/gswap.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=8&)

'도우미' 카테고리의 다른 글

리눅스 cpu, core 개수 확인  (0) 2011.10.06
(펌) rwlock  (0) 2011.08.17
(펌) 리눅스에서 2G 이상 파일 다루기  (0) 2011.08.10
difftime 날짜와 시간 차이 구하기  (0) 2011.07.29
strncpy  (0) 2011.02.20
출처 : http://blog.purewell.biz/2891022

리눅스 커널 2.4부터 2기가 파일제한이 풀렸다.

커널만 지원한다고 다 해결될 일이 아니다. 표준함수를 쓴다면 표준 라이브러리(glibc에 뭉쳐 있겠지?)가 지원해야한다. 다행히 표준 라이브러리는 2기가 이상 파일(large file이라고 한다)을 지원한다.

단, 다른 이름으로 제공한다. 예를 들어 fopen이 있으면 fopen64가 따로 있다. off_t 역시 off64_t가 따로 존재한다. 또한 이 라이브러리를 사용하고 싶다면 _LARGEFILE_SOURCE를 정의해야한다. 즉 컴파일 옵션에 -D_LARGEFILE_SOURCE를 포함해야한다.

ㅡ_-); 불편하다. 그냥 fopen == fopen64 이렇게 쓸 수 없나? 소스 안 고쳐도 되고 말이야.

그래서 _FILE_OFFSET_BITS가 있다. 컴파일 옵션에 -D_FILE_OFFSET_BITS=64를 하면 모든 *64 함수/변수형은 기존 이름으로 바뀐다. 즉 소스에 fopen이라고 쓰더라도 fopen64를 호출한다.

ㅡ_-); 결국 2기가 이상 파일을 쓰려면 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64를 옵션으로 써야한다. (테스트해보니 _FILE_OFFSET_BITS만 64로 정의했어도 잘 돌아간다.)

테스트 코드 (offset.c)
#include <stdio.h>
#include <unistd.h>

int
main(int,char**)
{
        printf("fopen: %p\n", fopen);
        printf("fopen64: %p\n", fopen64);
        printf("size of off_t: %d\n", sizeof(off_t));
        return 0;
}

컴파일 결과
32bit CPU
$ gcc -o offset offset.c
$ ./offset
fopen: 0x80483dc
fopen64: 0x80483cc
size of off_t: 4
(fopen과 fopen64의 함수 주소 값이 다르다)

$ gcc -o offset offset.c -D_FILE_OFFSET_BITS=64
$ ./offset
fopen: 0x80483a8
fopen64: 0x80483a8
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 같다)

64bit CPU (x86_64)
$ gcc -o offset offset.c
$ ./offset
fopen: 0x4004f0
fopen64: 0x400510
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 다르다)

$ gcc -o offset offset.c -D_FILE_OFFSET_BITS=64
$ ./offset
fopen: 0x4004c0
fopen64: 0x4004c0
size of off_t: 8
(fopen과 fopen64의 함수 주소 값이 같다)


Fedora Core 6에서 x86_64(64bit cpu) 깔아서 해봤더니 옵션 없을 때 off_t 크기가 8로 나오더군. 그러나 fopen과 fopen64 주소값이 다른 걸로 보아, 될 수 있으면 _FILE_OFFSET_BITS를 세팅해주는 센스를 발휘하는게 좋을 듯 싶다.

'도우미' 카테고리의 다른 글

(펌) rwlock  (0) 2011.08.17
(펌) 쉘스크립트 프로그래밍  (0) 2011.08.10
difftime 날짜와 시간 차이 구하기  (0) 2011.07.29
strncpy  (0) 2011.02.20
헷갈리는 printf  (0) 2011.02.18

설명

시간의 차이를 계산합니다. 예제에서는 2007년 7월 1일부터 프로그램을 시작하는 시간 까지의 일 수와 시간 차이를 구합니다.

헤더 time.h
형태 double difftime(time_t time1, time_t time0);
인수 time_t time1 시간 계산에서 빼어지는 시간
time_t time0 시간 계산에서 빼는 시간
반환 double 두 시간의 차이
예제
#include <stdio.h>
#include <time.h>

int main( void)
{
   time_t     tm_st;
   time_t     tm_nd;
   int        tm_day, tm_hour, tm_min, tm_sec;
   double     d_diff;
   struct tm  user_stime;

   user_stime.tm_year   = 2007   -1900;   // 주의 :년도는 1900년부터 시작
   user_stime.tm_mon    = 7      -1;      // 주의 :월은 0부터 시작
   user_stime.tm_mday   = 1;
   user_stime.tm_hour   = 10;
   user_stime.tm_min    = 12;
   user_stime.tm_sec    = 55;
   user_stime.tm_isdst  = 0;              // 썸머 타임 사용 안함

   tm_st = mktime( &user_stime);
   time( &tm_nd);

   d_diff   = difftime( tm_nd, tm_st);

   tm_day   = d_diff / ( 60 *60 * 24);
   d_diff   = d_diff - ( tm_day *60 *60 *24);

   tm_hour  = d_diff / ( 60 *60);
   d_diff   = d_diff - ( tm_hour *60 *60);

   tm_min   = d_diff / 60;
   d_diff   = d_diff - ( tm_min *60);

   tm_sec   = d_diff;

   printf( "2007년 7월 1일부터 지금까지는 %d일 %d시 %d분 %d초 지났음n", tm_day, tm_hour, tm_min, tm_sec);
   return 0;
}
]$ ./a.out
2007년 7월 1일부터 지금까지는 21일 18시 57분 9초 지났음
]$

'도우미' 카테고리의 다른 글

(펌) 쉘스크립트 프로그래밍  (0) 2011.08.10
(펌) 리눅스에서 2G 이상 파일 다루기  (0) 2011.08.10
strncpy  (0) 2011.02.20
헷갈리는 printf  (0) 2011.02.18
울트라에디트 구문강조 파일 wordfile.txt  (0) 2011.02.14


char *strncpy(char *dst, const char *src, size_t n);

뭐.. 특별히 위험한 점은 없으나, 세번째 인자보다 작은 문자열이 들어왔을 때,
그 차이만큼 '\0'로 계속 쓰게 되므로, 효율성에서 좋은 함수가 아닙니다.
게다가 n보다 크거나 같은 길이의 SRC가 들어올 경우, '\0'로 끝내주지 않으므로
일일히 검사하기도 번거롭습니다. 따라서 다음과 같이 만들어 두고 쓰는 것이 좋습니다:

char *
xstrncpy(char *dst, const char *src, size_t n)
{
  dst[0] = '\0';
  return strncat(dst, src, n - 1);
}


typedef struct _PRINTF_TEST
{
    char    a   [  1];
    char    b   [  2];
    char    c   [  3];
    char    d   [ 10];
    char    z   [ 50];
} PRINTF_TEST;

    PRINTF_TEST pt;
    memset(&pt, 0x00, sizeof(pt));
   
    memcpy(pt.a, "A"            , 1);
    memset(pt.b, 0x00           , 2);
    memcpy(pt.c, "CCC"          , 3);
    memcpy(pt.d, "12345"        , 5);
    memcpy(pt.z, "GGGGBEBEBEBE" , 12);

    printf("pt.a : s      [%s]\n", pt.a );
    printf("pt.b : s      [%s]\n", pt.b );
    printf("pt.c : s      [%s]\n", pt.c );
    printf("pt.d : s      [%s]\n", pt.d );
    printf("pt.d : z      [%s]\n", pt.z );

    printf("pt.a : -1s    [%-1s]\n", pt.a );
    printf("pt.b : -2s    [%-2s]\n", pt.b );
    printf("pt.c : -3s    [%-3s]\n", pt.c );
    printf("pt.d : -10s   [%-10s]\n", pt.d );
    printf("pt.z : -50s   [%-50s]\n", pt.z );  
    
    printf("pt.a : .1s    [%.1s]\n", pt.a );
    printf("pt.b : .2s    [%.2s]\n", pt.b );
    printf("pt.c : .3s    [%.3s]\n", pt.c );
    printf("pt.d : .10s   [%.10s]\n", pt.d );
    printf("pt.z : .50s   [%.50s]\n", pt.z );

    printf("pt.a : -.1s   [%-.1s]\n", pt.a );
    printf("pt.b : -.2s   [%-.2s]\n", pt.b );
    printf("pt.c : -.3s   [%-.3s]\n", pt.c );
    printf("pt.d : -.10s  [%-.10s]\n", pt.d );
    printf("pt.z : -.50s  [%-.50s]\n", pt.z );


-- NULL 만날때까지 출력
pt.a : %s      [A]
pt.b : %s      []
pt.c : %s      [CCC12345]
pt.d : %s      [12345]
pt.d : %s      [GGGGBEBEBEBE]

- 자리수까지는 NULL 무시, 자리수 이후 만나는 NULL에서 종료.
pt.a : %1s     [A]
pt.b : %2s     [  ]
pt.c : %3s     [CCC12345]
pt.d : %10s    [     12345]
pt.z : %50s    [                                      GGGGBEBEBEBE]

pt.a : %-1s    [A]
pt.b : %-2s    [  ]
pt.c : %-3s    [CCC12345]
pt.d : %-10s   [12345     ]
pt.z : %-50s   [GGGGBEBEBEBE                                      ]

-- 자리수만큼 출력, NULL 만나면 종료.
pt.a : %.1s    [A]
pt.b : %.2s    []
pt.c : %.3s    [CCC]
pt.d : %.10s   [12345]
pt.z : %.50s   [GGGGBEBEBEBE]

pt.a : %-.1s   [A]
pt.b : %-.2s   []
pt.c : %-.3s   [CCC]
pt.d : %-.10s  [12345]
pt.z : %-.50s  [GGGGBEBEBEBE]

'도우미' 카테고리의 다른 글

(펌) 리눅스에서 2G 이상 파일 다루기  (0) 2011.08.10
difftime 날짜와 시간 차이 구하기  (0) 2011.07.29
strncpy  (0) 2011.02.20
울트라에디트 구문강조 파일 wordfile.txt  (0) 2011.02.14
socket recv MSG_WAITALL  (0) 2011.02.10

int k, client_sock;
char dBuff[4096];

k = read(client_socket, dBuff, sizeof(dBuff));

이렇게 했거든요.. 근데... k값을 찍어보면 1046 정도로 나옵니다.
혹시 이런경우 있으신분.. 있나요?
해결하셨다면.... 문제점 지적해 주세요..


read함수대신에 recv함수를 이용해보세요.

k = recv(client_socket, dBuff, sizeof(dBuff), MSG_WAITALL);

MSG_WAITALL
This flag requests that the operation block until
the full request is satisfied. However, the call
may still return less data than requested if a sig
nal is caught, an error or disconnect occurs, or
the next data to be received is of a different type
than that returned.

'도우미' 카테고리의 다른 글

(펌) 리눅스에서 2G 이상 파일 다루기  (0) 2011.08.10
difftime 날짜와 시간 차이 구하기  (0) 2011.07.29
strncpy  (0) 2011.02.20
헷갈리는 printf  (0) 2011.02.18
울트라에디트 구문강조 파일 wordfile.txt  (0) 2011.02.14

+ Recent posts