이 글에서는 짧은 bash shell script 프로그램을 작성하여 실행해보도록 하겠다.

이 프로그램은 두 정수를 입력받아 두 정수 사이에 속하는 모든 소수의 합을 구하는 프로그램이다. 코드는 다음과 같다.

#!/bin/bash
let rst=0
echo -n "type two integers : "
read x y
if [ $x == $y ] #만약 두 숫자가 같다면 x, y사이에 값이 없으므로 0을 출력하고 종료
then
    echo 0
    exit 1
fi
if [ $x -gt $y ] //x보다 y가 작다면 둘이 숫자를 swap
then
    let tmp=$x
    x=$y
    y=$tmp
fi
let x++
while (( $x != $y )) #x가 y보다 작을 때까지
do
    if [ $x -eq 2 ] #2인 경우 추가
    then
        let rst+=2
        let x++
        continue;
    fi
    tmp=2 #나누는 수 2부터 시작
    until (( $tmp == $x )) #나누는 수가 x보다 작을 동안만 반복
    do
        let rest=$x%$tmp #나머지 계산
        if [ $rest -eq 0 ] #나누어 떨어지는 경우
        then
            break;
        fi
        let tmp++ #나누어 떨어지지 않는 경우
    done
    if [ $tmp -eq $x ] #2부터 x-1까지 x와 나누어 떨어지는 수가 하나도 없는 경우
    then
        let rst+=$x #rst에 x 더함
    fi
    let x++ #x 1 증가
done
echo "result : $rst"

큰 숫자가 먼저 나오는 경우도 올바르게 출력된다.

이 코드는 다음과 같이 실행된다.

1. x와 y가 같은지 확인한다. 같을 경우 0출력하고 종료

2. y가 x보다 큰지 확인한다. 그럴 경우 두 변수를 바꾼다.

3. x를 1씩 증가하며 y보다 작을 때까지 계산을 반복한다.

  3-1. x가 2인경우 rst에 x를 더한다.

  3-2. x가 소수인지 판별할 tmp변수를 2부터 x-1까지 1씩 증가하며 x와 나누어 떨어지는지 확인한다.

  3-3. 만약 나누어 떨어지는 수가 있는 경우 rst에 아무것도 더하지 않고 x를 1 증가시킨다.

  3-4. 만약 2부터 x-1까지 모든 수가 x와 나누어 떨어지지 않는 경우 rst에 x를 더한다.

 

위 실행 결과는 wsl2 ubuntu-20.04버전에서 실행한 결과이다.

    어떤 터미널 창을 열었을 때 우리는 쉘을 보게 된다. 이 쉘은 명령어를 입력하여 컴퓨터와 대화하는 프로그램이다. 이 쉘은 프로그램이기 때문에 어떤 터미널 창을 띄울 경우 하나의 프로세스라는 말이다. 리눅스, 맥 OS X에서 기본으로 사용되는 쉘은 Bash 쉘이다 이 Bash 쉘은 유닉스에서 사용되던 본 쉘(Bourne shell)을 GNU에서 확장하여 개발하였다. 이 글에서는 bash 쉘에서 사용하는 문법을 이용해 짧은 쉘 스크립트 프로그램을 짜는 방법을 알아볼 것이다.

    우선 쉘에서는 환경변수와 지역변수가 존재한다. 환경변수는 자식 프로세스에게 상속되는 변수이고 지역변수는 상속되지 않는 변수이다. bash shell창에 $ env를 통해 미리 정해진 환경 변수들을 살펴볼 수 있다. bash shell에서 다음과 같이 변수를 설정할 수 있다.

$ VAR=STRING
$ export VAR

첫 번째 줄과 같이 [변수명]=[문자열]로 지역변수를 설정할 수 있고 두 번째 줄과 같이 export [변수명]을 통해 설정한 지역변수를 환경변수로 만들 수 있다. 이때 주의해야할 점은 '=' 앞뒤에 공백이 있으면 안된다는 것이다.

또 리스트 변수를 선언할 수 있다. 리스트 변수는 다음과 같이 선언할 수 있다.

$ HERO=(LEESOONSHIN KIMYOUSHIN AHNJUNGKEUN YOUKWANSOON)
${HERO[i]} #리스트의 i번째 원소
${HERO[*]} #리스트의 모든 원소
${HERO[@]} #동일
${#HERO[*]} #리스트의 원소 개수
${#HERO[@]} #동일

첫 번째 줄과 같이 괄호( ) 안에 공백으로 원소를 구분하며 나열하여 선언할 수 있다. 그 아래와 같이 C언어와 비슷하게 대괄호 안에 원하는 인덱스의 번호를 주어 해당 원소에 접근할 수 있다. 만약 모든 원소를 사용하고 싶은 경우 인덱스 번호 대신 '*'나 '@'를 주면 된다. 마지막으로 원소의 개수는 모든 원소를 접근하는 방법에다가 리스트 변수명 앞에 '#'을 붙여 나타낼 수 있다. 실제 실행결과는 다음과 같다.

실제 실행 결과

echo라는 명령어는 뒤에 나오는 인자를 화면에 출력해주는 명령어이다. 따라서 변수를 줬을 때 변수의 값을 출력해준다. 변수를 접근하고자할 때는 변수명 앞에 '$'를 붙여줘야한다. 그렇지 않으면 문자열로 인식하여 다음과 같이 출력될 수 있다.

변수명 앞에 '$'를 붙이지 않을 경우

위 사진은 wsl2 Ubuntu-20.04에서 실행한 결과다. 다음 시간에는 이런 변수를 통해 짧은 shell script program을 짜보겠다.

리눅스 system call 함수를 이용하여 ls, chmod, touch명령어의 일부 기능을 수행하는 myls, mychmod, mytouch 명령어를 직접 만들어보았다. 명령어의 옵션이 상당히 많기 때문에 일부의 옵션만 구현하였다. 모든 프로그램은 system()이라는 system call함수를 사용하지 않았다.

소스코드는 글 맨 아래에 링크를 달아두었다.

    우선 ls의 명령어는 굉장히 많기 때문에 일부옵션인 l, i, t, a옵션만 구현하였다. 모든 옵션은 동시에 가능하다 예를 들면 myls -lit <filename|pathname>과 같이 사용할 수 있다. 만약 매개변수가 경로명일 경우 해당 경로에 있는 모든 파일들을 보여주고 매개변수가 파일명일 경우 해당 파일에 대한 ls명령어 결과를 보여준다.

'l' 옵션을 준 경우 파일에 대한 자세한 사항을 보여준다.

'a' 옵션을 준 경우 '.'으로 시작하는 파일을 포함하여 디렉토리에 있는 숨겨진 파일 전부를 보여준다.

't' 옵션을 준 경우 경로에 있는 파일을 시간순으로 정렬하여 출력한다.

'i' 옵션을 준 경우 파일의 i-node 번호를 앞에 출력해준다.

아래는 실행 결과이다.

ls명령어와 같이 myls를 실행했을 때 현재 디렉토리의 모든 파일을 보여준다.
-l 옵션을 주어 실제 ls명령어와 결과 비교
-lit 옵션을 주었을 때 ls명령어와 결과 비교
-l 옵션을 주었을 경우 symbolic 디렉토리일 경우  실제로 가리키는 디렉토리가 -> 뒤에 나타난다.
setuid bit가 설정된 파일의 경우 x대신 s가 나타난다.

chmod 명령어는 숫자, 알파벳 모두 옵션으로 사용할 수 있도록 구현하였다. 따라서 다음과 같이 사용할 수 있다.

mychmod g+r <filename>

mychmod 644 <filename>

프로그램 내부에서는 chmod()라는 system call함수를 이용하여 파일의 접근권한을 수정한다. mychmod를 실행하기 전과 후에 ls명령어를 이용하여 파일 정보를 확인한다면 결과가 접근권한이 바뀌어있는 것을 확인할 수 있을 것이다.

아래는 실행 결과이다.

mychmod로 접근권한을 751로 바뀌게 했을 경우 실행 이전과 비교
뒤에 3자리 접근권한 앞에 1일 경우 stickybit를, 2일 경우 setgid bit, 4일 경우 setuid비트를 설정할 수 있다.
문자를 이용하여 접근권한을 바꿀 경우 결과이다.

    마지막으로 touch명령어는 굉장히 간단한 프로그램이다. 파일이 없을 경우 생성만 하면 되고 'c' 옵션의 경우 파일이 없을 경우 파일을 생성하지 않으면 된다. 만약 파일이 있을 경우 파일의 access, modify, change 시간을 현재 시간으로 갱신하기만 하면 된다. 이때 시간 변경은 utime()이라는 system call 함수를 이용하여 두 번째 인자로 NULL을 주어 자동적으로 현재 시간으로 수정하게 하면 된다. utime()함수는 access와 modify시간만 변경 가능하다. 따라서 현재 시간을 받아 그 시간 변수를 인자로 넘길 경우 각 줄을 실행하는 딜레이로 인해 change시간이 access와 modify의 시간과 다르게 갱신될 수 있다.

https://github.com/Seo-sang/LinuxSystemProgramming_ls_chmod_touch.git

 

Seo-sang/LinuxSystemProgramming_ls_chmod_touch

Contribute to Seo-sang/LinuxSystemProgramming_ls_chmod_touch development by creating an account on GitHub.

github.com

 

+ Recent posts