블로그 이미지
progh2
지루한 것에서 벗어나 재미난 것 속으로 풍덩~☆

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

Recent Post

Recent Comment

Archive

break - for, while, until 루프문 빠져나가기

continue - for, while, until 루프문에서 한회 건너 뛰기

# - 주석

: - 널(null) 명령. 조건문의 논리를 단순화하기 위해 true 대신 사용되기도.
while :
do
...
done

: 구조는 조건적인 변수의 설정에 사용되기도 한다.
아래 내용은 var에 값이 없을경우 value를 대입한다. 앞의 :가 없으면 $var를 명령으로 평가하려고 하기 때문에 :를 써주어야 한다.
: ${var:=value}
이럴 때도 사용하기도 한다.
#!/bin/sh
rm -f fred
if [ -f fred ]; then
:
else
echo file fred did not exist
fi
exit 0

. - 현재 쉘에서 명령 실행
일반적으로 스크립트가 외부 명령이나 스크립트를 실행할 때는 새로운 환경(서브쉘)이 생성되어 새로운 환경에서 실행되기 때문에 그 환경은 부모 쉘로 반환되는 종료코드 외에는 무시되어버린다. 그러나 .명령은 현재 쉘에서 실행된다. 이것은 나중에 실행할 다른 어떤 명령을 위한 환경을 설정하기 위해 스크립트를 '랩퍼(wrapper)'로 사용할 때 종종 유용한데, 예를들면 동시에 여러 프로젝트를 작업중이라면 기존의 프로그램을 다루기 위한 구 버전의 컴파일러를 호출하는 등과 같은 때 사용할 수가 있다.

#!/bin/sh
# classic_set.sh
version=classic
PATH=/usr/local/old_bin:/usr/bin:/bin:.
PS1="classic>"

#!/bin/sh
# latest_set.sh
version=latest
PATH=/usr/local/new_bin:/usr/bin:/bin:.
PS1="latest version>"
$ . ./classic_set
classic> echo $version
classic
classic> . latest_set.sh
latest version> echo $version
latest
latest version>
eval - 인수를 평가하여 변수값의 값을 준다.
[CODE]#!/bin/bash foo=10 x=foo y='$'$x echo $y eval y='$'$x echo $y[/CODE]
exec - 현재 쉘을 다른 프로그램으로 대체
예를들어, 스크립트에서 다음은 현재 쉘을 wall 명령으로 대체할 것이다. 스크립트를 실행중이던 쉘은 더 이상 존재하지 않으므로 스크립트에서 exec 다음의 어떤 문장도 실행되지 않는다.
exec wall "Thanks for all the fish"
exit n - 스크립트가 종료 코드 n을 가지고 종료한다.
종료코드를 지정하지 않고 종료하면, 최종 실행된 명령의 상태가 반환값이 된다. 0은 성공을 가르키고, 코드 1부터 125까지는 스크립트에 의해 사용될 수 있는 에러코드이다. 즉 125개의 사용자 정의 에러코드를 사용가능한 것이다. 나머지 값은 이미 예약된 의미를 가진다.
종료코드 설명
126 파일이 실행 가능하지 않았다
127 명령이 발견되지 않았다.
128 이상 시그널이 발생했다.
export - 파라미터로 지정된 변수를 서브 쉘에서 유효하게 만든다.
export 명령은 파라미터로부터 환경 변수를 생성하는데 이 변수는 현재 프로그램이 호출하는 다른 스크립트와 프로그램에서 사용할 수 있다. 기술적으로 표현하면 익스포트된 변수는 쉘로부터 파생되는 어떤 자식 프로세스에서 환경 변수를 형성한다.
[CODE]#!/bin/sh # export2.sh echo "$foo" echo "$bar"[/CODE]
[CODE]#!/bin/sh # export1.sh foo="The first meta-syntatic variable" export bar="The second meta-syntatic variable" ./export2.sh[/CODE]

실행결과
$ ./export1.sh

The second meta-syntatic variable
$
명령 set -a나 set -allexport는 모든 변수를 export한다.
[CODE]#!/bin/sh # export3.sh set -a foo="The first meta-syntatic variable" export bar="The second meta-syntatic variable" ./export2.sh[/CODE]
실행결과
$ ./export3.sh
The first meta-syntatic variable
The second meta-syntatic variable
$
posted by progh2
쉘 프로그래밍 - 함수, 내장명령, 명령결과, heredocument
함수
[CODE]function_name () { statements }[/CODE]
함수를 호출하기 위해서는 항상 함수를 먼저 정의해야 한다. 함수가 호출될 때 스크립트의 위치 파라미터 $*, $@, $#, $1, $2 ... 등은 함수에 대한 파라미터에 의해 대체된다. 이게 함수로 전달된 파라미터를 읽어들이는 방법이며 함수가 끝날 때 이전 파라미터로 값이 복원된다. 또한 return 명령을 사용하여 함수가 숫자값을 반환하게 할 수 있다. 함수가 스트링을 반환하게 하는 일반적인 방법은 함수가 끝난 후에도 사용할 수 있도록 스트링을 변수에 저장하게 하는 방법이 있다.
[CODE]#!/bin/bash foo() { ls -al asd * return } result=$(foo) for keyword in $result do echo $keyword done[/CODE]
결과
[CODE]ls: asd: 그런 파일이나 디렉토리가 없음 -rwxr-xr-x 1 progh2 progh2 25 7월 18 19:34 a.sh -rwxr--r-- 1 progh2 progh2 304 7월 18 21:54 andor.sh [/CODE]
local variable
local 키워드를 사용하면 전역변수와 별개의 지역변수를 쓸 수 있다.
[CODE]#!/bin/sh sample_text="global variable" foo() { local sample_text="local variable" echo "function foo is executing" echo $sample_text smaple_text="also this is local variable" echo $sample_text } echo "script starting" echo $sample_text foo echo "script ended" echo $sample_text exit 0[/CODE]
파라미터 전달 예
yes_or_no 로 파라미터를 넘기는 것과 넘겨진 것의 변화를 살펴본다. 또한 함수의 반환값을 if에 사용한 것도 주의.
[CODE]#!/bin/bash yes_or_no() { echo "Is your name $* ?" while true do echo -n "Enter yes or no: " read x case "$x" in y | yes ) return 0;; n | no ) return 1;; * ) echo "Answer yes or no" esac done } echo "Original parameters are $*" if yes_or_no "$1" then echo "Hi $1, nice name" else echo "Oh, never mind." fi exit 0[/CODE]
posted by progh2
리스트
and 리스트 구조 - 이전의 모든 명령이 성공적이었다면 다음 명령을 실행하며 일련의 명령을 실행하게 해준다.
statement1 && statement2 && ...
각 문장은 왼쪽에서부터 실행되고, 이것이 true를 반환하면 오른쪽 다음 문장이 실행도니다. 이런 과정이 false를 반환할 때까지 계속된다. &&는 이전 명령의 조건을 테스트한다.

or 리스트 구조 - 하나의 명령이 성공할 때까지 일련의 명령을 실행
statement1 || statement2 || ...
각 문장은 왼쪽에서부터 실행되며 false를 반환하면 오른쪽의 문장이 실행, true를 반환할 때까지 계속되며 true를 반환하면 멈추게 된다.
[CODE]#!/bin/sh # and list touch file_one rm -f file_two if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there" then echo "in if" else echo "in else" fi # or list rm -f file_one if [ -f file_one ] || echo "hello" || echo " there" ; then echo "in if" else echo "in else" fi exit 0[/CODE]
or 리스트 구조에서 결과를 결정하기 위해 최소의 문장들이 실행된다. 이것을 흔히 최단 평가 (short circuit evaluation)이라고 한다.
and 와 or 구조를 결합한 유용한 사용법
테스트가 성공적이면 전자를, 실패하면 후자를 실행
[ -f file_one ] && command for true || command for false
문장블록
and나 or 리스트에서 다음과 같이 한 문장이 허용되는 경우에 여러 문장을 사용하기 원한다면 문장 블록을 만들기 위해 중괄호{}에 문장을 포함시킬 수 있다.
get_confirm && {
grep -v "$cdcatnum" $tracks_file > $temp_file
cat $temp_file > $tracks_file
echo
add_record_trakcs
}
posted by progh2
변수
기본적으로 모든 변수는 숫자값을 가지는 경우에도 스트링으로 간주, 필요에 따라 적절히 숫자로 인식할 것이다. 또한 대소문자를 구분하며 변수에 값을 부여할 때를 제외하고는 변수 앞에 $ 문자를 추가할 필요가 있다. 또한 스트링에 빈 칸이 포함된다면 큰 따옴표를 사용해야 한다. 그리고 값을 부여시 등호 양쪽에 빈칸이 없어야 한다.
[CODE]#!/bin/sh myvar="Hi rhere" echo $myvar echo "$myvar" echo '$myvar' echo $myvar echo Enter some text read myvar echo '$myvar' now equals $myvar exit 0[/CODE]
환경변수 - 쉘 스크립트가 시작될 때 초기화되는 환경의 값들을 가진 변수.
[CODE]$HOME 현재 사용자의 홈 디렉토리 $PATH 명령을 검색하는 디렉토리들의 목록. 콜론으로 구분 $PS1 대개 $인 명령 프롬프트 $PS2 추가적인 입력을 요구할 때 사용되는 2차 프롬프트. 대개 > $IFS 입력필드구분자. 쉘이 입력을 받아들일 때 단어를 구분하는 데 사용하는 문자의 목록으로, 대개 빈 칸, 탭, 새 줄 문자이다. $0 쉘 스크립트의 이름 $# 전달된 파라미터의 수 $$ /tmp/tmpfile_$$와 같이 종종 독특한 임시 파일 이름을 생성하기 위해 스크립트에서 사용하는 쉘 스크립트의 프로세스 ID[/CODE]

파라미터 변수
[CODE]$1, $2, ... 스크립트에 주어진 파라미터 $* 환경 변수 IFS의 첫 문자로 구분되고, 하나의 변수에 저장되는 모든 파라미터의 목록 $@ IFS 환경 변수를 사용하지 않는 $*에 대한 변형 [/CODE]

조건
test와 [] - 조건이 만족되었는지의 여부를 가리키는 test 명령의 종료코드는 조건적인 코드가 실행되었는지를 결정한다.
if test -f fred.c
then
...
fi
위와 같은 뜻..
if [ -f fred.c ]; then
...
fi
[]와 테스트되는 조건 사이에 빈칸이 추가되어야 한다.

스트링비교
string1 = string2 두 스트링이 같으면 참
string1 != string2 두 스트링이 같지 않으면 참
-n string 두 스트링이 널이 아니면 참
-z string 두 스트링이 널(빈 스트링)이면 참
산술비교
ex1 -eq ex2 두 수식이 같으면 참
ex1 -ne ex2 두 수식이 같지 않으면 참
ex1 -gt ex2 ex1이 ex2보다 크면 참
ex1 -ge ex2 ex1이 ex2보다 크거나 같으면 참
ex1 -lt ex2 ex1이 ex2보다 작으면 참
ex1 -le ex2 ex1이 ex2보다 작거나 같으면 참
! exp 두 수식이 거짓이라면 참 (또는 그 반대)
파일 조건
-d file 파일이 디렉토리면 참
-f file 파일이 파일이면 참 ( -e 대용으로도 많이 쓰인다. )
-e file 파일이 존재하면 참
-r file 파일이 읽기가능하면 참
-w file 파일이 쓰기가능이면 참
-x file 파일이 실행가능이면 참
-g file 파일에 set-group-id가 설정되면 참
-u file 파일에 set-user-id가 설정되면 참


프로그램 제어
if - 예문 하나로 설명 끝.
[CODE]#!/bin/sh echo " Is it mornig? Please answer yes or no" read timeofday if [ "$timeofday" = "yes" ]; then echo "Good morning" elif [ "$timeofday" = "no" ]; then echo "Good afternoon" else echo "Sorry, $timeofday not recognized. Enter yes or no" exit 1 fi exit 0[/CODE]
[ $timeofday = "no" ] 식으로 표현할 경우 변수값이 null 이면 [ = "no" ] 식이 되버려 에러가 발생하므로 "$timeofday" 라고 표현해주어야 한다.
for
for variable in values
do
statements
done

[CODE]#!/bin/sh for file in $(ls f*.sh); do echo $file done exit 0[/CODE]
while
while condition
do
statements
done

[CODE]#!/bin/sh foo=1 while [ "$foo" -le 20 ] do echo "$foo Here we go again" foo=$(($foo+1)) done exit 0[/CODE]
until
[CODE]until condition do statements done[/CODE]

[CODE]#!/bin/bash until who | grep "$1" > /dev/null do sleep 60 done # 경고음을 내고 사용자에게 알려준다. echo -e \a echo "*** $1 has just logged in ***" exit 0[/CODE]
case
[CODE]case var in pattern [ | pattern ] ...) statements;; pattern [ | pattern ] ...) statements;; ... esac[/CODE]

[CODE]#!/bin/bash echo "Is it morning? Please answer yes or no" read timeofday case "$timeofday" in [yY] | [yY][eE][sS] ) echo "Good Morning";; [nN] | [nN][oO] ) echo "Good Afternoon";; * ) echo "Sorry, answer not recognized" exit 1;; esac exit 0[/CODE]
posted by progh2
출력 재지정
> 덮어쓰기
>> 파일에 추가
표준 ,에러 출력 재지정
ls a * > lsout.txt 2> lserr.txt
>& 표준, 에러 출력의 결합
ls a * > lsouterr.txt 2>&1
출력 버리기(bit bucket 사용)
ls a * > /dev/null 2>&1

권한주기
$ chmod u=rwx,go=rx first.sh
유닉스에서는 파일이 있는 디렉토리에 대해 쓰기 권한을 가질 경우 파일을 삭제할 수 있다는 것을 기억하기 바란다. 안전한 상태가 되기 위해서는 안전하게 유지하기를 원하는 디렉토리에 대한 쓰기 권한을 root에만 부여하는 것이 좋다.
posted by progh2
유닉스 철학에 대해 다룬 내용. 번역이 어색한 부분이 있지만 =_= 취지를 이해하며 그냥 넘어가자. 단순성과 필터와 개방형 파일방식 부분에 대해서는 크게 공감이 간다.



출처 - 비기닝 리눅스 프로그래밍
C로 프로그래밍하는 것은 어떤 플랫폼에서든지 많은 점에서 비슷하지만, 유닉스 개발자들은 프로그램과 시스템 개발의 특별한 관점을 가지게 된다.
유닉스 운영체제는 독특한 프로그래밍 스타일을 요구한다. 다음은 전형적인 유닉스 프로그램과 시스템에서 제공하는 몇 가지 특성이다.

단순성 : 가장 유용한 많은 유닉스 유틸리티는 매우 간단하고, 그 결과 작고 이해하기 쉽다. KISS(Keep It Small and Simple)는 배우기 좋은 기술이다. 크고 복잡한 시스템은 더 크고 복잡한 버그를 가질 수 있고, 모든 개발자들은 디버깅을 원하지 않을 것이다!

집중성 : 프로그래밍 한 가지 일을 제대로 수행하도록 만드는 것이 더 좋다. "다양한 특징"을 가지는 프로그램을 사용하거나 다루는 것은 어려울 수 있다. 한 가지 목적을 가지는 프로그램은 더 나은 알고리즘이나 인터페이스가 개발될 때 개선하기도 쉽다. 유닉스에서는 하나의 큰 프로그램을 통해 사용자의 요구에 대응하기보다는 종종 필요할 때마다 더 많은 요구에 부응하기 위해서 여러 작은 유틸리티를 함께 사용한다.

재사용이 가능한 컴포넌트 : 애플리케이션의 핵심이 라이브러리를 통해 유효하도록 만들기 바란다. 간단하지만 융통성 있는 프로그래밍 인터페이스를 가지고 체계적으로 문서화된 라이브러리는 다른 사람들이 변형판을 만들거나, 새로운 애플리케이션 분야에 해당 기술을 적용하도록 도와줄 것이다. 예를들어, 단일 데이터베이스 관리 프로그램이 아니라 재사용이 가능한 함수의 모음인 dbm 데이터베이스 라이브러리가 있다.

필터 : 많은 유닉스 애플리케이션은 필터로 사용될 수 있다. 즉, 입력을 받아들이고 출력을 생성한다. 유닉스는 색다른 방법으로 여러 프로그램을 결합하여 아주 복잡한 애플리케이션을 개발하게 해주는 특징을 제공한다. 물론, 이런 형태의 재사용은 방금 설명한 개발 방식에 의해 가능한 것이다.

개방형 파일 형식 : 매우 성공적이고 유명한 유닉스 프로그램은 평범한 ASCII 텍스트의 환경 설정파일과 데이터 파일을 사용한다. 프로그램을 개발할 떄 이런 평범한 조건이 주어진다면 아주 좋을 것이다. 이것은 사용자들이 환경 설정 항목을 변경하고 검색하기 위해 표준 도구를 사용할 수 있게 하고 데이터 파일에 대해 새로운 기능을 수행하기 위한 새 도구의 개발을 쉽게 해준다. 이것의 좋은 예는 기호의 위치에 대한 정보를 검색 프로그램에서 사용할 수 있는 일반적인 수식으로 기록하는 ctags 라는 소스 코드 상호 참조 시스템이다.

융통성 : 사용자들이 프로그램을 얼마나 정교하게 사용할 것인지를 정확히 예상하는 것은 불가능하다. 프로그램을 개발할 때에는 가능한 융통적이어야 한다. 필드나 레코드의 수에 임의의 제한을 설정하지 않기 바란다. 가능하다면, 프로그램을 네트워크와 관련시키고, 지역 컴퓨터뿐 아니라 네트워크에서도 실행할 수 있게 작성하기 바란다. 결코 사용자들이 모든 것을 잘 알고 있다고 스스로 자만심을 갖지 않기 바란다.
posted by progh2
출처 - 비기닝 리눅스 프로그래밍 2nd

정적 라이브러리의 한 가지 단점은 많은 프로그램을 실행하고 각각이 모두 같은 라이브러리의 함수를 사용할 때, 메모리에 같은 함수의 많은 사본이 존재하게 되고, 결국 프로그램 파일 자체가 많은 함수의 사본을 가지게 된다는 문제가 있다. 이러한 문제를 해결한 것이 공유라이브러리의 개념이다.
공유라이브러리는 정적 라이브러리와 같은 장소에 저장되며 고유한 확장자를 가진다. 전형적인 리눅스 시스템에서 표준 C 공유 라이브러리는 /lib/libc.so.N 이다. 여기서 N은 주 버전을 뜻하며 현재 6이다.
프로그램이 공유 라이브러리를 사용할 때는 함수 코드 자체를 가지는 것이 아니라 실행 시에 유효한 공유 코드에 대한 참조를 가지도록 링크된다. 그 결과로 프로그램이 실행되고 메모리에 로드될 때 함수에 대한 참조가 이루어지며 필요에 따라서 메모리 내에 로드되는 공유 라이브러리에 대해서 함수 호출이 수행된다. 이러한 방법은 하나의 공유 라이브러리가 한번에 많은 어플리케이션에 의해 사용되고 디스크에 하나만 존재하면 된다. 추가적인 이득은 이 라이브러리가 의존하는 프로그램에 상관없이 독립적으로 갱신될 수 있다는 것이다.



ldd
동적 로더는 리눅스 시스템에서 공유 라이브러리를 로드하고 클라이언트 프로그램의 함수 참조를 해결하는 일을 다루는 프로그램이다. ld.so 나 ld-linux.so.2 등이 있으며 공유 라이브러리를 찾기 위해 검색하는 추가 위치를 /etc/ld.so.conf 에 설정하고 ldconfig로 갱신할 수 있다. ldd를 사용하여 프로그램에 필요한 공유 라이브러리를 확인할 수도 있다.
$ ldd program
manpage
http://man.kldp.org/wiki/FrontPage?action=GetManPage&lang=ko&man=ldd&sec=all

공유 라이브러리는 많은 점에서 마이크로소프트 윈도우즈에 사용되는 동적링크 라이브러리와 비슷하다. .so 라이브러리는 .DLL 파일에 대응하고 실행시에 요구되는 반면, .sa 라이브러리는 프로그램 실행 파일에 호함되는 .LIB 파일과 비슷하다.
posted by progh2
출처 - 비기닝 리눅스 프로그래밍 2nd

아래 4개의 파일이 있다고 할 때..
fred.c
[CODE]/* fred.c */ #include <stdio.h> void fred(int arg) { printf("fred: you passed %d ", arg); }[/CODE]
bill.c
[CODE]/* bill.c */ #include <stdio.h> void bill( char *arg) { printf("fred: you passed %s ", arg); }[/CODE]
lib.h
[CODE]/* lib.h */ void bill(char *); void fred(int);[/CODE]
program.h
[CODE]/* program.c */ #include "lib.h" int main() { bill("Hello World"); exit(0); }[/CODE]
컴파일..
[CODE]$ cc -c fred.c $ cc -c bill.c $ cc -o program program.c bill.o[/CODE]


ar
Static Library를 만들 때 사용한다. 사용법은 다음과 같다.
(bill.o 와 fred.o 두 오브젝트 파일을 합쳐 libfoo.a 를 만들고자 할 때 )
ar crv libfoo.a bill.o fred.o
manpage
http://man.kldp.org/wiki/GetManPage?action=GetManPage&lang=en&man=ar


ranlib
정적 라이브러리를 성공적으로 사용하기 위해서 일부 시스템, 특히 버클리(Berkeley) 유닉스로부터 파생된 시스템에서는 라이브러리 목차를 만들 필요가 있는데, 이를 위해 ranlib을 사용한다. 리눅스와 같이 GNU 소프트웨어 개발 도구를 사용할 때에는 이러한 것이 필요하지 않으며 또한 실행한다 하더라도 문제가 없다.
ranlib libfoo.a

manpage
http://man.kldp.org/wiki/GetManPage?action=GetManPage&lang=en&man=ranlib



정적라이브러리의 사용
이렇게 만든 정적라이브러리는 다음과 같이 사용할 수 있다.
cc -o program program.o libfoo.a
또는
cc -o program program.o -L. -lfoo
-L. 옵션은 컴파일러엑 라이브러리를 현재 디렉토리에서 찾도록 지시한다. -lfoo 옵션은 컴파일러에게 libfoo.a라는 라이브러리를 사용하도록 지시하고, 공유라이브러리인 libfoo.so가 존재한다면 이것을 사용하게 한다.



nm
오브젝트 파일, 라이브러리, 실행 프로그램에 어떤 함수들이 포함되는지 살펴보기 위해서는 nm 명령을 사용할 수 있다.
nm program
nm libfoo.a

manpage
http://man.kldp.org/wiki/GetManPage?action=GetManPage&lang=en&man=nm
posted by progh2