상세 컨텐츠

본문 제목

UNIX - 파일 및 디렉터리 조작하기

Computer Science/UNIX

by 2021. 10. 15. 21:22

본문

반응형

sys/stat.h

파일의 상태에 대한 정보를 얻거나 설정

  • 해당 파일이 저장된 디바이스 번호
  • 해당 파일의 inode 번호
  • 해당 파일의 Mode
  • 해당 파일 소유자의 User ID
  • 해당 파일 소유자의 Group ID
  • 해당 파일의 하드 링크 개수
  • 해당 파일의 블록 크기
  • 해당 파일의 블록 개수
  • 해당 파일을 마지막으로 액세스한 시간
  • 해당 파일을 마지막으로 편집한 시간

example

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
	struct stat buf;
	if(argc > 1)
	{
		printf("Arguments is not allowed! \n");
		return 1;
	}
	printf("argv[0]: %s \n", argv[O]);
	stat(argv[0], &buf);

	printf("Mode: %lo \n", (unsigned long)buf.st_mode); // Type & Protection
	printf("UID: %d \n", (int)buf.st_uid); // User ID of the File
	printf("Size: %d \n", (int)buf.st_size); // Size of the File
	printf("Modification Time: %d \n", (int)buf.st_mtime); // Latest Modification Time
	
    return 0;
}

Mode는 파일 타입과 접근 허가(=파일 속성)

result

assist@assist-VirtualBox:~/Unix_Programming$ ls -l fstat
-rwxr-xr-xX 1 assist assist 8496 10월 1 19:07 fstat
assist@assist-VirtualBox:~/Unix_Programming$ fstat
argv[®]: fstat
Mode: 100755
UID: 10660
Size: 8496
Modification Time: 1569924462

 

Mode가 100755라는 의미 중 앞의 100~은 위 그림의 S_IFREG 즉 regular file이라는 의미이다.

하드 링크와 심볼릭 링크

하드 링크 (Hard Link)

  • 파일에 대한 별명(alias)
  • 파일 이름이 다르다 해도 같은 내용을 가리킴
  • 파일의 소유자만이 생성할 수 있음

심볼릭 링크 (Symbolic Link)

  • 유닉스에서의 ‘바로가기’
  • 누구나 생성가능
  • 원본 파일이 없으면 링크가 깨짐

하드 링크 만들기 & 지우기

<unistd.h>

int link(const char *old, const char *new)

  • old 파일을 new 파일에 하드 링크
  • old와 new는 같은 파일을 가리킴

int unlink(const char *path)

  • path로 지정된 하드 링크를 제거
  • 마지막 남은 링크인 경우 사실상 파일을 삭제

리턴 값 : 0이면 성공, 아니면 실패

example (mv.c)

#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
	if(arge != 3)
	{
		perror("Usage: ./mv <old> <new> \n");
		return -1;
	}
	if(link(argv[1], argv[2]))
	{
		printf("Link failed. : %s -> %s \n", argv[1], argv[2]);
		return -2;
	}
	/*
	 if(unlink(argv[1]))
	{
		printf("Unlink failed. : %s \n", argv[1]);
		return -3;
	}
	*/
	printf("File moved: %s -> %s \n", argv[1], argv[2]);
	return 0;
}

result

assist@assist-VirtualBox:~/Unitx_Programming$ ls -1 fstat
-rwxr-xr-xX 1 assist assist 8496 10월 1 19:07 fstat
assist@assist-VirtualBox:~/Unix_Programming$ ./mv fstat fstat2
File moved: fstat -> fstat2
assist@assist-VirtualBox:~/Unix_Programming$ ls -l fstat*
-rwxr-xr-x 2 assist assist 8496 10월 1 19:07 fstat
-rw-r--r-- 1 assist assist 558 10월 1 19:07 fstat.c
-rwxr-xr-x 2 assist assist 8496 10월 1 19:07 fstat2

fstat 파일의 link count가 1에서 2로 증가하고, fstat2도 link count가 2인 것을 확인

디렉터리 만들기

<sys/types.h>, <sys/stat.h>

int mkdir(const char *pathname, mode_t mode)

  • pathname : 생성할 디렉터리 경로
  • mode : 생성할 디렉터리의 권한
  • 리턴 값 : 0이면 성공, 아니면 실패

example (md.c)

#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
	int i;
	for(i = 1 3; i < argc ; ++i)
		mkdir(argv[i], 0777);
	return 0;
}

result

assist@assist-VirtualBox:~/Unix_Programming$ ./md dir1 dir2
assist@assist-VirtualBox:~/Unix_Programming$ ls -1
합계 120
-rwxr-xr-x 1 assist assist 8440 10월 1 21:45 cd
-rw-r--r-- 1 assist assist 345 10월 1 22:26 cd.c
drwxr-xr-x 2 assist assist 4096 10월 1 22:30 diri
drwxr-xr-x 2 assist assist 4096 10월 1 22:30 dir2

코드에서 permission을 0777로 작성했으나 생성된 permisison은 0755이다. 

이는 defulat umask가 0022이기 때문이다.

system call chmod

chmod(파일명, 권한)

  • sys/stat.h 헤더에 포함
  • 파일명 : 권한을 바꿀 대상 파일
  • 권한 : 덮어쓸 권한을 설정

umask

umask(마스크)

  • 파일이나 디렉터리를 만들 때 권한을 마스킹
  • 마스크 역시 8진수 형식으로 설정
  • 최종 권한 : 0777 & ~마스크

실제 결과는 open()을 해야 확인 가능하다

example (md_umask.c)

#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
	int i;
	umask(0000); // mask: 000
	for(i = 1 ; i < argc ; ++i)
		mkdir(argv[i], 0777);
	return 0;
}

result

assist@assist-VirtualBox:~/Unix_Programming$ ./md dir_md
assist@assitst-VirtualBox:~/Unix_Programming$ ./md_umask dir_md_umask
assist@assist-VirtualBox:~/Unix_Programming$ ls -1
합계 88
drwxr-xr-x 2 assist assist 4096 10월 1 20:58 dir_md
drwxrwxrwx 2 assist assist 4096 10월 1 20:58 dir_md_umask
-rwxr-xr-x 1 assist assist 8296 10월 1 20:43 md
-rw-r--r-- 1 assist assist 155 10월 1 26:43 md.c

디렉터리 지우기

<unistd.h>

int rmdir(const char *pathname)

  • pathname : 삭제할 디렉터리 경로
     디렉터리는 반드시 비어 있어야 함
  • 리턴 값 : 0이면 성공, 아니면 실패

example (rm.c)

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	int i, res;
	dup2(1, 2); // stderr에 stdout 덮어씀
	for(i = 1; t < argc ; ++i)
	{
		res = rmdir(argv[i]);
		if(res)
			printf ("rmdir for %s failed. \n", argv[i]);
	}
	return 0;
}

result

unix@unixsystem:~$ ls -1
total 32
drwxr-xr-x 2@ unix unix 4096 Oct 13 20:18 dir1
drwxr-xr-x 2 unix unix 4096 Oct 13 20:18 dir2
-rwxr-xr-x 2 unix unix 5016 Oct 13 20:09 md
-rw-r--r-- 41 unix unix 157 Oct 13 20:08 md.c
-rwxr-xr-x 2 unix unix 5157 Oct 13 20:18 rm
-rw-r--r-- 1 unix unix 215 Oct 13 20:17 rm.c
unix@unixsystem:~$ ./rm diri dir2 dir3
rmdir for dir3 failed.
unix@unixsystem:~$ ls -1
total 24
-rwxr-xr-x 1 unix unix S016 Oct 13 20:09 md
-rw-r--r-- 1 unix unix 157 Oct 13 20:08 md.c
-rpwxr-xr-x% 1 unix unix 5157 Oct 13 20:18 rm
-rw-r--r-- 2 unix unix 215 Oct 13 20:17 rm.c
unix@unixsystem:~$ _

디렉터리 위치 변경

<unistd.h>

int chdir(const char *pathname)

  • pathname : 이동할 디렉터리 위치
  • 리턴 값 : 0이면 성공, 아니면 실패
  • 디렉터리 위치는 현재 프로세스에 한정

int fchdir(int fd)

  • fd : 이동할 디렉터리의 파일 서술자
  • 나머지는 chdir()과 동일

디렉터리 위치 확인

<unistd.h>

char* getcwd(char *name,size_t size)

  • name : 현재 위치를 저장할 포인터이자 리턴 값
  • size : name의 크기 (충분히 커야 함)

example (cd.c)

#finclude <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
	char name[256];
	int i, res;
	
    printf ("Current Dir.: %s \n", getcwd(name, 256));
	for(i = 1; i < arge ; ++i)
	{
		res = chdir(argv[i]);
		if(res)
			printf("Chdir for %s failed. \n", argv[i]);
		else
			printf("Current Dir.: %s \n", getcwd(name, 256));
	}
	return 0;
}

result

unix@unixsystem:~$ ./cd /tmp /var /usr/include ~
Current Dir. : /home/unix
Current Dir. : /tmp
Current Dir. : /var
Current Dir. : /usr/include
Current Dir. : /home/unix
unix@unixsystem:~$ _

디렉터리 엔트리

Unix에서는 모든 것을 파일로 관리함

  • 일반 파일, 블록 파일, 디렉터리 파일, 장치 파일…

디렉터리는 특수한 형태의 파일

디렉터리 엔트리는 디렉터리를 표현하는 데에 쓰이는 자료구조

디렉터리에 속한 파일들은 디렉터리 엔트리, 구조체로 관리

디렉터리 엔트리 구조

struct dirent
{
#ifndef __USE_FILEOFFSET64 // 64비트 사용
	__ino_t d_ino; // 파일 엔트리 번호(inode)
	__off_t d_off; // 파일 오프셋 (offset)
#else // 32비트 사용
	__ino64_t d_ino; // inode (64비트 강제)
	__off64_t d_off; // offset (64비트강제)
#endif
	unsigned short int d_reclen; // 파일 이름의 길이
	unsigned char d_type; // 파일 타입
	char d_name [256] ; // 파일 이름
};

디렉터리 열기

<dirent.h>

DIR *opendir(const char *pathname)

  • pathname : 디렉터리의 경로
  • 리턴 값 : NULL이면 실패, 아니면 성공

int closedir(DIR *dirp)

  • 열려있던 디렉터리를 닫음

디렉터리 읽기

<dirent.h>

struct dirent *readdir(DIR *dirp)

  • dirp : 열려 있는 디렉터리 포인터
  • 리턴 값 : 디렉터리 엔트리 (NULL이면 실패)
  • 디렉터리의 엔트리를 하나 읽어옴
  • 읽은 뒤에는 다음 엔트리로 넘김

void rewinddir(DIR *dirp)

  • dirp의 포인터를 처음으로 되돌림

example (list.c)

#include <dirent.h>
#include <stdio.h>

int main(int argc, char* argv[]){
	int res, depth = 0;
	DIR* dirp;
	struct dirent* entry;

	if(arge != 2){
		perror("Usage: list <path> \n");
		return -1;
	}
	
	dirp = opendir(argv[1]);
	if(dirp == NULL){
		perror("Directory cannot be opened. \n");
		return -2;
	}
	while((entry = readdir(dirp)) != NULL)
		printf("%101ld : %s \n", entry->d_ino, entry->d_name);
	closedir(dirp);
	return 0;
}

result

unix@unixsystem:“$ ./list .
    570 : ..
    293 : md.c
    294 : cd.c
    450 : cd
    452 : list
    1055 : .bash_history
    4610 : .
    321 : rm.c
    26205 : .profile
    31360 : .bashre
    384 : rm
    432 : md
    33103 : .bash_logout
    326 : list.c
unix@unixsystem:~$ —

현재 디렉터리에 대한 inode 번호와 파일명이 모두 표시

(현재와 상위 디렉터리도 표시)

Background에서 작업 수행하기

Ctrl + Z

  • 현재 foreground에서 실행 중인 작업을 중지시킴
    assist@assist-VirtualBox:~/Unix_Programming$ ./bg
    Knock!
    
    ^Z
    [1]+ Stopped
    assist@assist-VirtualBox:~/Unix_Programming$​

&

  • 명령어 뒤에 &를 붙이면 background에서 작업을 수행함
    assist@assist-VirtualBox:~/Unix_Programming$ ./bg &
    [2] 16871
    Knock!
    assist@assist-VirtualBox:~/Unix_Programming$
    Knock!​

명령어 – jobs

jobs

  • Background에서 실행되는 작업목록 (Job ID, 상태, 명령어)을 보여주는 명령어
assist@assist-VirtualBox:~/Untix_Programming$ jobs
[1]+ Stopped		./bg
[2]- Running		./bg &
  • Job ID는 PID와는 별도로 부여되는 번호
  • 작업목록은 현재 shell session에 딸린 것이며,
    다른 session 과는 독립적이다.

job 명령어에는 다음과 같은 상태들이 있다

명령어 - bg

bg %(ID)

  • Stopped 된 작업을 백그라운드에서 수행시킴
  • 사용법 : bg %JobID
assist@assist-VirtualBox:~/Unix_Programming$ jobs
[1]+ Stopped		./bg
[2]- Running		./bg &
assist@assist-VirtualBox:~/Unix_Programming$ bg %1
[1]+ ./bg &
Knock!

assist@assist-VirtualBox:~/Unix_Programming$ Knock!

Knock!

Knock!

명령어 - fg

fg %(ID)

  • Background에서 수행중인 작업을 Foreground로 옮김
  • 사용법 : fg %JobID
assist@assist-VirtualBox:~/Unix_Programming$ fg %1
./bg
Knock!

jobs
Knock!

Knock!

명령어 – kill

kill

  • 작업을 끝내거나, 프로세스를 종료시키는데 사용
  • 사용법
    kill %JobID : 수행중인 Job종료시킴
    kill PID : 해당 프로세스 ID를 가진 프로세스를 종료
assist@assist-VirtualBox:~/Unix_Programming$ jobs
[2]+ Running		./bg &
assist@assist-VirtualBox:~/Unix_Programming$ kill %2
[2]+ Done		./bg
assist@assist-VirtualBox:~/Unix_Programming$ jobs
assist@assist-VirtualBox:~/Unix_Programming$

명령어 – kill -9

kill -9

-9 옵션은 강제종료(권장 X)

assist@assist-VirtualBox:~/Unix_Programming$ vi &
[1] 17614
assist@assist-VirtualBox:~/Unix_Programming$ jobs
[1]+ Stopped		vi
assist@assist-VirtualBox:~/Unix_Programming$ kill -9 %1
[1]+ Killed		vi
assist@assist-VirtualBox:~/Unix_Programming$ jobs
assist@assist-VirtualBox:~/Unix Programming$
반응형

관련글 더보기