본문 바로가기

Developments/Linux

[Linux 실습] Ch7. 파일 유틸리티들(File Utilities)

오픈 소스 비영리 기관 'Open Source Initiative'의 로고. https://opensource.org/

본 글은 학교 '오픈소스 소프트웨어 입문' 과목을 수강하며 실습(또는 공부)한 내용을 정리한 글입니다.

개인 기록 용도로 작성한 글이라, 직접 이 글을 보고 실습을 따라하기엔 어려움이 많을 것으로 예상됩니다.
혹시 본 글을 보며 Linux를 공부하실 목적이라면, 일단 키워드 위주로 AI에게 물어봐가면서, 본인의 Linux 터미널에서 직접 타이핑해가며 공부하시기를 추천드립니다.

질문이나 의견이 있다면 자유롭게 댓글 달아주세요!

Command

wc	line,word, char count
tr	translate or delete char
split -l	split file into piece
head	head of lines of files
tail	tail of file (-f for tracking) 
diff	compare filecmp/comm
sort	sort lines
join -i	join lines of two files on a common field
uniq 	report omit repeated line
cut	remove section from file
stat	file status

Complex scripting

awk, gawk

Compression / Archive

tar	tape archive
rar
rpm
gzip, gunzip, gcat	
zip/unzip
uuencode/uudecode
winzip
ppt
wc 는 알거고(순서대로 줄, 단어 수, 문자 개수, 파일 이름 출력)
tr 은 문자 변환에 씀.
예시: echo "hello world" | tr ' ' '\\t'
이 명령어는 "hello world"에서 공백을 탭 문자로 바꿔서 출력해요.

split -l는 파일을 특정 줄 수마다 쪼갠다는 명령어라고함.
예시: split -l 10 largefile.txt
이 명령어는 largefile.txt 파일을 10줄씩 나눠서 여러 개의 파일로 분리해요.
생성된 파일은 xaa, xab, xac 등으로 이름이 붙습니다.

head tail은 처음이나 끝부분만 출력
diff 는 두 파일을 비교하는 거임.
예시: diff file1.txt file2.txt

sort 는 정렬
그냥 sort file.txt 하면, file.txt의 내용이 사전순 오름차순 정렬돼서,
stdout로 출력됨. (했던 거 기억나지??)

join -i는 그 옆에 딱 붙이고 싶은거라함
두 개의 파일을 특정 기준으로 합치는 명령어입니다. 
기본적으로는 두 파일의 첫 번째 필드를 기준으로 합칩니다. 
이 명령어는 구분자가 공백일 때 작동하며, 
구분자가 다른 경우 -t 옵션으로 구분자를 지정할 수 있습니다.
1 apple
2 banana
3 cherry
1 red
2 yellow
3 red
join file1.txt file2.txt
1 apple red
2 banana yellow
3 cherry red

uniq는 hello world 같은 게 10번 나올 경우, 그걸 1번만 보고 싶으면
또는 함수 실행 후 공백 대 여섯 개씩 넣어 두는 애들 싫잖음 uniq 쓰기

cut - 텍스트에서 특정 필드를 잘라내는 명령어입니다. 
주로 구분자가 있는 텍스트 파일에서 특정 필드를 추출할 때 사용됩니다.
예시: cut -d ',' -f 1,3 file.csv
file.csv에서 첫 번째와 세 번째 필드를 추출해 출력합니다.
-d 옵션은 **구분자(delimiter)**를 지정하는 데 사용됩니다.
-f 옵션은 **출력할 필드(field)**를 지정하는 데 사용됩니다.
1,apple,red
2,banana,yellow
3,cherry,red
cut -d ',' -f 1,3 file.csv
1,red
2,yellow
3,red

stat - 파일의 상세 정보를 확인할 수 있는 명령어입니다. 
파일의 크기, 수정 시간, 접근 권한 등을 출력합니다.
 File: a.out
  Size: 16696           Blocks: 40         IO Block: 4096   regular file
Device: 802h/2050d      Inode: 2512382     Links: 1
Access: (0755/-rwxr-xr-x)  Uid: ( 3110/ foss110)   Gid: ( 3000/    foss)
Access: 2025-03-27 03:51:13.896900474 +0900
Modify: 2025-03-20 10:00:05.062535960 +0900
Change: 2025-03-20 10:00:05.062535960 +0900
a.out: ELF 64-bit LSB shared object, x86-64, 

참고) file은 파일의 타입을 알려줌. 아래 저거 원래 한줄.
a.out: ELF 64-bit LSB shared object, x86-64, 
version 1 (SYSV), dynamically lind, interpreter 
/lib64/ld-linux-x86-64.so.2, 
BuildID[sha1]=5694eafb0e3ab3d74c78479bfb8fbc0cf506b6, 
for GNU/Linux 3.2.0, not stripped

winzip 윈도우식 압축. Windows 환경에서 압축을 풀고 만들 때 사용.
gzip는 좀 압축 많이 된거라는듯. 압축률이 높아 큰 파일을 많이 줄여줌. 
무손실 압축. -9 옵션 달면 최고 압축률로 압축해줌.
압축 풀려면 gunzip사용. gunzip file.gz

awk gawk 는 굉장히 고급스러운 명령어.
저 이름 3명 딴 건데, 세 분 다 구루 분들임.
운체 교수님, 등등

---실습---

cat hello.c

cat hello.c hello.c hello.c 하면 저게 3번 붙여져서 출력됨.
cat hello.c hello.c hello.c > hello3

이 cat은 원래는 저렇게 파일 concat 용도였으나, 
concat한 결과를 stdout에 출력해준다는 점에서 착안해,
그냥 출력으로도 쓰게 됨. 아님 리다이렉션으로 파일에 내용 쓰거나.

man cat하면 저거 cat [OPTION]... [FILE]... 임.
즉, FILE에 브라켓이 들어가 있음. 필수가 아님.
-> 파일이 없거나, 파일 부분에 -가 들어가 있으면, stdin을 읽어들인다!!!!
즉, scanf하고 있는 상태인 거임.

그리고, EOF가 들어오면 입력 받는 걸 끝냄.
이 EOF 시그널을 키보드로 보낼 수 있는데,
리눅스는 Ctrl d, 윈도우는 Ctrl d.
리눅스의 Ctrl z는 다른 거니까 누르지 ㄴㄴ.

cat > myTyping 하면, 내가 입력한 것들이 파일로 다 저장됨.
vi 에디터를 내가 정 못쓰겠으면, 저거로라도 hello.c를 만들 순 있겠다.

한 줄 복사할 때 vi에서 yy임. yank.
붙여넣기는 p.

uniq 하면 이전 줄의 stdiout 출력과 같은 줄이 출력됐으면,
출력하지 않는다.
uniq hello.c 해보고,
uniq 직접 입력 100 200 300 ... 해보자.
uniq 하고 100 100 100 하면 두 번째부터는 출력이 안됨.
sort 그냥 하면, 입력 stdin 받아서 EOF 받을 시 마지막에 사전순 오른차순 출력.

cd ~foss000
echo foss110 >> att0320
tail -f att0320 # 이거 업데이트된 것들이 맨 끝으로 계속 유지하며 보여줌.
# -f 옵션: "follow"라는 의미로, 파일의 변화가 있을 때마다 계속해서 새로운 내용을 출력하는 옵션이야.
ctrl c

오늘 tar과 stat는 꼭 알아야 한다.
mkdir lab0325

우리가 만약 디렉토리를 실수로 날려버렸으면?
-> backup을 받아야 함.

백업 명령어중에 유닉스/리눅스에서 제일 간단하고 많이 쓰이는게 tar임.

원래 예전엔 테이프를 썼는데, 백업디바이스는 싸고 용량이 크고
그 예시가 테이프였음.
만약 2시간마다 백업한 걸 받아야 하면, 그럼 백업디바이스를 쓰면 안됨.
그냥 디스크를 하나 더 들여놓고 쓰는 게 합리적.
백업은 막 200시간마다 파일이 깨져서 백업하는 그런 느낌임.

tar은 tape archive의 약자.
tar은 백업을 만들기도 하고 백업한 내용을 보기도 하고 
백업한 걸 받아오는 데도 쓰임.

tar cvf backup0325.tar lab*
백업 생성, 백업 진행상황 출력, 백업파일 이름 backup0325.tar로 정함.
저거 마지막에 그냥 .하면 좀 복잡해짐. 그래서 우린 그냥
globbing 쓸 거다. lab으로 시작하는 모든 파일 백업.

참고) v는 verbose인데, 주저리 주저리 말이 많다는 뜻임.
즉, 너가 뭘 하고있으면, 하고 있는 거 진행상황을 주저리주저리 써라.
f 옵션 다음에는 바로 지정할 백업파일이름이 나와야 함.

참고2) . 대신 *lab 쓴 이유
이 명령어는 현재 디렉토리 안에 있는 모든 파일과 폴더를 백업하지만, 
예상치 못한 파일이나 디렉토리가 포함될 수 있습니다. 
예를 들어, 숨김 파일(.git, .bashrc) 등도 포함될 수 있습니다.
따라서, lab* 와 같은 패턴을 사용하면 더 정확한 파일들만 
백업할 수 있어 편리합니다.

foss110@ajousw:~$ ls -al
total 148
drwx------  13 foss110 foss  4096 Mar 25 10:41 .
drwxr-xr-x 153 foss000 foss  4096 Mar 25 10:28 ..
-rw-r--r--   1 foss110 foss     0 Mar 11 11:11 (검열)
drwxr-xr-x   3 foss110 foss  4096 Mar 18 11:44 backup0318
**-rw-r--r--   1 foss110 foss 61440 Mar 25 10:41 backup0325.tar**
-rw-------   1 foss110 foss  8399 Mar 24 23:11 .bash_history
-rw-r--r--   1 foss110 foss   232 Jul 22  2024 .bash_logout
-rw-r--r--   1 foss110 foss  3788 Jul 22  2024 .bashrc
drwx------   2 foss110 foss  4096 Mar  6 10:32 .cache
drwx------   3 foss110 foss  4096 Mar  6 10:32 .config
drwxr-xr-x   2 foss110 foss  4096 Mar 11 11:30 lab0311
drwxr-xr-x   3 foss110 foss  4096 Mar 17 05:32 lab0313
drwxr-xr-x   3 foss110 foss  4096 Mar 18 11:41 lab0318
drwxr-xr-x   2 foss110 foss  4096 Mar 20 10:17 lab0320
drwxr-xr-x   2 foss110 foss  4096 Mar 25 10:33 lab0325
drwx------   3 foss110 foss  4096 Mar  6 10:32 .local
drwx------   9 foss110 foss  4096 Jul 24  2024 Maildir
-rw-r--r--   1 foss110 foss   657 Jul 22  2024 .profile
drwxr-xr-x   2 foss110 foss  4096 Mar 18 11:24 .vim
-rw-------   1 foss110 foss  8514 Mar 20 10:17 .viminfo

tar tvf backup0325.tar 입력하면 백업파일의 내용 볼 수 있음.
t는 table of contents로, tar 파일의 내용을 확인.

여기서, 지금 디렉토리에서 tar xvf backup0325.tar 해버리면 안됨.
그러면 기존에 김대리가 백업 시점 이후부터 지금까지 수정해둔 
파일들 다 옛날로 돌아감. 수정사항은 반영하고싶음.
즉, 백업 이후 수정사항 건들지 말고 백업한 걸 받아오고 싶으면??
-> 일단 다른 디렉토리에 백업 풀고 거기서 뽑아와라.

참고로, 백업 파일 mv하지 말고, cp 하셈. 디스크가 젤 싸다.
(왜 cp가 더 좋지? 확인) -> 걍 안전하게 cp하라는듯.

mkdir tmp
cp backup0325.tar tmp
cd tmp
tar xvf backup0325.tar
이제 tmp 폴더에서 백업을 받아왔음(풀었음).

참고) 덮어쓰기를 Clobbering(클로버링)이라고 부름. ex) > 덮어쓰기

여기서, ls -lR하면 recursive하게 디렉토리 내부까지 찾아줌.
ls -lR lab* > listCurrent
cd tmp
cd lab0313
touch file (아무거나 바꾸겠다)
cd ..
cd ..
ls -lR lab* > listCurrent
diff listCurrent tmp/list0325back

foss110@ajousw:~$ !diff
diff listCurrent tmp/list0325back
17c17
< -rw-r--r-- 1 foss110 foss    9 Mar 13 09:30 file
---
> -rw-r--r-- 1 foss110 foss    9 Mar 25 10:50 file
18a19
> -rw-r--r-- 1 foss110 foss    0 Mar 25 10:52 list0325back
29c30
< -rwxrwxrwx 2 foss110 foss   22 Mar 18 11:15 file
---
> -rwxr-xr-x 2 foss110 foss   22 Mar 18 11:15 file
31c32
< -rwxrwxrwx 2 foss110 foss   22 Mar 18 11:15 hlink
---
> -rwxr-xr-x 2 foss110 foss   22 Mar 18 11:15 hlink
36c37
< dr-xrwxrw- 2 foss110 foss 4096 Mar 18 10:36 test
---
> dr-xr-xr-- 2 foss110 foss 4096 Mar 18 10:36 test

여기서, 참고로, 어떤 파일을 cp떴으면, 두 파일은 inode가 
완전히 다름. 그러니까 다르다고 나오는 거임 두 파일들이.
->  cp는 새 파일을 생성한 후, 원본 파일의 데이터를 복사하기 때문
✔️ 새로운 파일이므로, 파일 시스템이 새로운 inode 번호를 할당함
-> 당연!! inode가 달랐다면, 사실상 같은 파일이잖음.
그럼 하나를 수정하면 다른 것도 수정되게 됨.
만약 같은 inode를 공유하는 복사를 원하면 
ln(하드 링크) 명령어를 사용해야 함.

여기서, 저 diff를 보고 이제 원래 폴더에 복구하면 되는데,
복구하기 전에도 지금 원래 폴더에 있는 걸 백업해야 함.
왜냐면 잘못 복구할 수도 있으니까.
백업의 rule을 grandfather rule이라고 부르는데,(꼼꼼하게)
1. 많이 한다.
2. 자주 한다.
3. 백업 파일에 라벨링을 한다.(테이프라고 치면 포스트잇 붙이기)
(이 때, 백업하는 백업 디바이스는 신뢰성이 매우 강한 디바이스여야 함)
(뭐 금고에 넣어두든.)

참고) 권한이 바뀐 이유는, umask 가 022이기 떄문.
파일 권한:
일반적으로 새로 생성되는 파일의 권한은 666 (rw-rw-rw-)에서
umask 값을 제외한 값입니다.
예를 들어, umask가 0022이면, 새 파일은 666에서 022를 제외한 
644 권한 (rw-r--r--)을 갖게 됩니다.
디렉토리 권한:
디렉토리의 경우 기본 권한은 777 (rwxrwxrwx)에서 
umask 값이 제외된 결과로 설정됩니다.
예를 들어, umask가 0022일 때, 새로 생성되는 디렉토리는 
777에서 022를 제외한 755 권한 (rwxr-xr-x)을 갖게 됩니다.

근데, 여기서 원본 파일 권한이 777이었어서 복구 시 022가 빼짐.

du -sh *
0       (검열)
16K     backup0318
60K     backup0325.tar
4.0K    lab0311
20K     lab0313
16K     lab0318
52K     lab0320
20K     lab0325
4.0K    listCurrent
80K     Maildir
164K    tmp

📌 du -sh * 명령어 설명
해당 명령어는 현재 디렉터리에 있는 모든 
파일 또는 디렉터리의 크기를 요약하여 출력합니다.

🔍 du -sh 옵션 분석
du (disk usage) : 파일 및 디렉터리의 디스크 사용량을 표시

-s (summary) : 각 디렉터리의 총 사용량만 출력 
(하위 파일 개별 크기 생략)

-h (human-readable) : 사람이 읽기 쉬운 단위
(예: KB, MB, GB)로 출력

저 tar파일 용량 줄이고 싶으면,
gzip -9 backup0325.tar
-9: 최대 압축률로 압축.
61440B -> 4024B 확 줄어들음.
backup0325.tar.gz가 됨.

stat backup0325* (.tar.gz 생략)
foss110@ajousw:~$ stat backup0325*
  File: backup0325.tar.gz
  Size: 4024            Blocks: 8          IO Block: 4096   regular file
Device: 802h/2050d      Inode: 2518373     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 3110/ foss110)   Gid: ( 3000/    foss)
Access: 2025-03-25 10:42:52.659763989 +0900
Modify: 2025-03-25 10:41:48.255746390 +0900
Change: 2025-03-25 11:00:57.815471889 +0900
 Birth: -

  File: backup0325.tar.gz   # 파일 이름
  Size: 4024               # 파일 크기 (바이트 단위, 4KB)
  Blocks: 8                # 디스크 블록 수 (1블록 = 512B 또는 4KB)
  IO Block: 4096           # I/O 블록 크기 (기본 4KB)
  regular file             # 파일 유형 (일반 파일)
  
  Device: 802h/2050d       # 파일이 위치한 디바이스 번호
  Inode: 2518373           # 파일의 inode 번호 (파일 시스템에서의 고유 ID)
  Links: 1                 # 하드 링크 수 (1이면 하드 링크 없음)
  
  Access:  (0644/-rw-r--r--)  # 파일 권한 (소유자 읽기/쓰기, 그룹&기타 읽기 가능)
  Uid: ( 3110/ foss110)       # 파일 소유자 (UID 3110, foss110)
  Gid: ( 3000/    foss)       # 그룹 소유자 (GID 3000, foss)
  
  Access:  2025-03-25 10:42:52  # 마지막 접근 시간 (atime)
  Modify:  2025-03-25 10:41:48  # 마지막 수정 시간 (mtime)
  Change:  2025-03-25 11:00:57  # inode 변경 시간 (ctime)
  Birth: -                       # 생성 시간 (리눅스에서는 표시되지 않음)

1. 하드 링크 개수
일반 파일은 1개의 링크 카운트(자기 자신)
하드 링크를 추가하면 링크 카운트 증가
2. 디렉터리의 경우 링크 카운트 계산법
디렉터리는 .(자기 자신)과 ..(부모 디렉터리) 때문에 \\
기본적으로 2 이상의 링크 카운트를 가짐

하위 디렉터리가 추가될 때마다 링크 카운트가 증가
foss110@ajousw:~$ ln lab0325 hdir
ln: lab0325: hard link not allowed for directory
-> 디렉토리는 하드 링크를 생성할 수 없음.
그냥 디렉토리를 하드 링크 하면 좀 이상할 거 같으니까,
디렉토리에 하드링크하면 에러 메시지 출력하고 끝내자고 정한 건데,
왜 그런 판단을 내린 걸까? 하드 링크 해도 괜찮지 않나?
-> 리눅스 파일 구조는 기본적으로 트리 구조잖아.
그럼 루트 하나에 위에서 아래로 쭉 가는 건데,
디렉토리 간 하드 링크가 있다는 건, 아래에서 위로 연결되는
direct path가 있다는 거임.
-> 그러면 이건 트리가 아니라 modified tree가 되어버림.

또한, 하드 링크를 디렉토리에 허용해버리면 이거 같은 폴더가 돼버리는데
좀 많이 헷갈린다.

위 두 이유는 교수 생각임. 근데 그럴싸함.

파일은 하드 링크를 허용하는 이유??)
파일에 하드 링크가 허용되는 이유는 파일이 단일 데이터 블록으로 
존재하며, 여러 경로에서 참조하더라도 시스템의 계층적 트리 구조를 
왜곡하지 않기 때문입니다. 하드 링크는 단지 파일에 대한 또 다른 
경로일 뿐입니다.
반면에 디렉토리에 하드 링크를 만들면, 부모-자식 관계와 계층적 
트리 구조를 깨뜨리는 순환 참조가 발생할 수 있기 때문에 
디렉토리에 대해서는 하드 링크를 허용하지 않는 것입니다.

winzp 배우기 전에, 가져오는 명령어 하나 배워보자.

터미널 하나 새로 열어서, 
우리 학교 서버에 있는 backup0325.tar.gz를 cp로 
내 pc로 가져오고 싶음.

scp foss110@ssh.ajousw.kr:~/backup0325.tar.gz .
-> 현재 디렉토리에 cp하는 명령어가 scp.
secure copy의 줄임말로 ssh를 이용하여 
네트워크로 연결된 호스트간에 파일을 주고받는 명령어.
내 컴퓨터에 가져와졌음.

이제, gz를 어떻게 압축을 풀까?
-> gunzip backup0325.tar.gz

이거 우리 컴터(git bash)에서도 gunzip 가능함.
민쥐에 저 프로그램이 포함돼있음.

이제, mkdir tmp
mv *.tar tmp (근데 아까 cp하라 하긴 했는데, 교수는 걍 mv했음)
(왜냐면 이미 백업이 서버에 있기도 하고 걍 공부하는거니까)

근데, tar명령어가 없는 사람은 곤란하잖음.
그러니 winzip을 써서,
winzip -f back0325.zip lab* 하면 됨.
근데 지금 서버에 winzip없어서 안됨.
나중에 교수가 찾아보고 다시 한다 함.