데이터는 디스크에 쓰인다. 디스크는 추상화된 파일 시스템, 이를테면 ext4NTFS, 아니면 ReFS같은 곳에서 추상화된 방식으로 섹터, 혹은 SSD라면 어떤 블록 위에 작성된다. 그리고 ls -la같은 것으로 출력되는 파일 이름은 이 데이터에 접근하기 위한 엔트리포인트가 된다. 여기서는 복잡한 파일 시스템에 대해서는 나중에 알아보기로 하고 단순히 파일과 링크에 대해서만 적어 보자. 파일 시스템에 관련된 내용만 적어도 한세월이다.

참고로 윈도우에서도 마찬가지로 심볼릭(소프트)링크와 하드 링크 둘 다 비슷한 개념으로 존재한다.

하드 링크

디스크 내 데이터를 가리키는 파일을 하나 더 만든다. 무슨 뜻인가 하면, 보통 파일을 지우는 경우 데이터를 가리키는 엔트리포인트가 더는 없으므로 데이터에 접근할 방법이 (일반적으로는) 없어지지만, 하드 링크를 통해 이를 더 추가할 수 있다. 따라서 파일 A의 하드링크 B를 만든 경우, A와 B를 가리키는 디스크의 데이터가 같아서, A를 사용하여 데이터를 수정하더라도 B를 사용하여 데이터를 확인하였을 때 그 데이터가 같다는 뜻이다. 같은 데이터를 가리키기 위해 inode를 사용한다. inode를 통해 파일이 디스크에 어떤 데이터를 가리킬 수 있으며, 이는 ls -i 혹은 stat을 통해 확인 가능하다.

$ ls -lai
합계 28
17567778 drwxrwxr-x  2 cublr cublr  4096  1월  2 21:43 .
 6553602 drwxr-xr-x 74 cublr cublr  4096  1월  2 21:43 ..
17568138 -r--------  1 cublr cublr 18000  1월  2 21:06 important.data
$ ln important.data linked.data
$ ls -lai
합계 48
17567778 drwxrwxr-x  2 cublr cublr  4096  1월  2 21:43 .
 6553602 drwxr-xr-x 74 cublr cublr  4096  1월  2 21:44 ..
17568138 -r--------  2 cublr cublr 18000  1월  2 21:06 important.data
17568138 -r--------  2 cublr cublr 18000  1월  2 21:06 linked.data

important.datalinked.data의 inode는 17568138로 둘 다 같음을 알 수 있다. 따라서 이 두 파일은 사실상 같은 파일이다. 따라서 하나의 파일을 뭔가 조작하더라도 다른 파일에 영향이 간다. 예를 들어 파일 권한을 조정하는 경우 important.data를 변경하더라도 linked.data 또한 함께 변경된다.

$ chmod 644 important.data
$ ls -lai
합계 48
17567778 drwxrwxr-x  2 cublr cublr  4096  1월  2 21:43 .
 6553602 drwxr-xr-x 74 cublr cublr  4096  1월  2 21:45 ..
17568138 -rw-r--r--  2 cublr cublr 18000  1월  2 21:06 important.data
17568138 -rw-r--r--  2 cublr cublr 18000  1월  2 21:06 linked.data

하드 링크가 얼마나 됐는지를 확인하기 위해 find -inum N 명령을 호출하거나 stat을 사용한다. find같은 경우 여기저기 흩어져 있는 동일한 inode를 찾기 위해 쓰이고, stat의 경우에는 지금 파일의 현황을 파악하기 위해 쓰는 것 같다.

$ stat important.data
  File: important.data
  Size: 18000     	Blocks: 40         IO Block: 4096   일반 파일
Device: 10302h/66306d	Inode: 17568138    Links: 2
Access: (0644/-rw-r--r--)  Uid: ( 1000/cublr)   Gid: ( 1000/cublr)
Access: 2022-01-02 21:26:18.961066395 +0900
Modify: 2022-01-02 21:06:06.766347964 +0900
Change: 2022-01-02 21:45:35.492312043 +0900
 Birth: -
$ rm -rf linked.data
$ stat important.data
  File: important.data
  Size: 18000     	Blocks: 40         IO Block: 4096   일반 파일
Device: 10302h/66306d	Inode: 17568138    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/cublr)   Gid: ( 1000/cublr)
Access: 2022-01-02 21:26:18.961066395 +0900
Modify: 2022-01-02 21:06:06.766347964 +0900
Change: 2022-01-02 21:48:14.259195655 +0900
 Birth: -

stat의 결과로 Links가 2인 것을 확인할 수 있다. 링크 하나를 지운 경우 다시 1로 줄어들었다.

소프트 링크

리눅스에서는 심볼릭 링크라고도 부른다. 실제 파일의 inode를 같게 만들거나 하지 않고, 그 파일의 경로를 가리키는 특별한 파일을 생성한다.

$ ls -la
합계 28
drwxrwxr-x  2 cublr cublr  4096  1월  2 21:48 .
drwxr-xr-x 74 cublr cublr  4096  1월  2 21:50 ..
-rw-r--r--  1 cublr cublr 18000  1월  2 21:06 important.data
$ ln -s important.data linked.data
$ ls -la
합계 28
drwxrwxr-x  2 cublr cublr  4096  1월  2 21:50 .
drwxr-xr-x 74 cublr cublr  4096  1월  2 21:50 ..
-rw-r--r--  1 cublr cublr 18000  1월  2 21:06 important.data
lrwxrwxrwx  1 cublr cublr    14  1월  2 21:50 linked.data -> important.data
$ stat linked.data
  File: linked.data -> important.data
  Size: 14        	Blocks: 0          IO Block: 4096   심볼릭 링크
Device: 10302h/66306d	Inode: 17568143    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: ( 1000/cublr)   Gid: ( 1000/cublr)
Access: 2022-01-02 21:50:40.354213055 +0900
Modify: 2022-01-02 21:50:39.426219186 +0900
Change: 2022-01-02 21:50:39.426219186 +0900
 Birth: -

원본 파일이 삭제되면 심볼릭 링크가 가리키는 대상이 없으므로 잘못된 링크가 된다. ls -la로 파일 리스트를 체크해 보면 색이 다르거나 잘못되었다는 식으로 바로 표시되므로 알아볼 수 있다. bash에서 체크하거나 할 경우 if -L -e을 사용한다. 파일이 심볼릭 링크인지를 확인하기 위해서는 readlink를 사용해볼 수 있다.

$ cat test.sh
my_link=$1

if [ -L $my_link ] && [ -e $my_link ]; then
    echo "file exists"
else
    echo "not exists"
fi
$ ./test.sh test.sh
not exists
$ ./test.sh important.data
not exists
$ ./test.sh linked.data
file exists
$ readlink linked.data
important.data
$ readlink important.data
$ echo $?
1 # important.data는 심볼릭 링크가 아니므로 에러를 출력한다.
$ rm -rf important.data
$ ./test.sh linked.data # 원본 파일 important.data를 지우면 linked.data는 잘못된 링크가 된다.
not exists