find
find 명령은 파일 검색과 관련해 사용할 수 있는 많은 옵션들을 제공합니다. 필요로 하는 옵션에 대해서는 man 페이지를 참조하시고 여기서는 기본적인 find 명령의 사용법에 대해서 알아보겠습니다. 앞으로 설명을 위한 명령 실행에는 아래와 같은 디렉토리 구조를 대상으로 하겠습니다.
오른쪽의 -depth
( depth first ) 옵션은 디렉토리 보다 contents ( 파일명 ) 가 먼저 출력되게 합니다.
-delete
액션을 이용해 파일 및 디렉토리를 일괄 삭제할 때 자동으로 설정됩니다.
왼쪽같이 디렉토리가 먼저 출력되는 것은 -prune
액션을 이용해 특정 디렉토리를
검색에서 제외할 때 유용합니다.
$ find $ find -depth
. ./dir_1/foo.html
./dir_1 ./dir_1/foo.txt
./dir_1/foo.html ./dir_1
./dir_1/foo.txt ./index.txt
./index.txt ./.hidden.txt
./.hidden.txt ./.git/git.html
./.git ./.git/git.txt
./.git/git.html ./.git
./.git/git.txt ./dir_2/dir_3/bar_2.html
./dir_2 ./dir_2/dir_3/bar_2.txt
./dir_2/dir_3 ./dir_2/dir_3
./dir_2/dir_3/bar_2.html ./dir_2/bar_1.html
./dir_2/dir_3/bar_2.txt ./dir_2/bar_1.txt
./dir_2/bar_1.html ./dir_2
./dir_2/bar_1.txt ./index.html
./index.html .
위의 출력에서 보는 것과 같이 find 명령은 아무런 인수를 주지 않으면 find .
과 같습니다.
따라서 출력의 앞부분에 ./
가 포함되는데 이것이 필요하지 않을 경우 다음과 같이 하면 됩니다.
# 디렉토리, 파일명을 직접 적어준다.
$ find dir_1
dir_1
dir_1/foo.html
dir_1/foo.txt
# 또는 디렉토리 전체를 검색하려면 다음과 같이 shell globbing 을 사용하면 됩니다.
# "*" glob 문자는 기본적으로 "." 으로 시작하는 hidden 파일은 매칭에 포함되지 않기 때문에
# .git 디렉토리 내용은 포함되지 않는 것을 볼 수 있습니다.
$ find *
dir_1
dir_1/foo.html
dir_1/foo.txt
dir_2
dir_2/dir_3
dir_2/dir_3/bar_2.html
dir_2/dir_3/bar_2.txt
dir_2/bar_1.html
dir_2/bar_1.txt
index.html
index.txt
# "." 로 시작하는 파일도 매칭에 포함하려면 다음과 같이 합니다.
$ find -printf '%P\n' # %P 는 패스에서 처음 디렉토리를 제거하는 역할을 하므로 './' 가 제거된다.
# 또는 # 그대로 포함하려면 소문자 %p 사용
$ find * .*[^.]*
. . .
. . .
dir_2/dir_3/bar_2.txt
dir_2/bar_1.html
dir_2/bar_1.txt
index.html
index.txt
.git
.git/git.html
.git/git.txt
.hidden.txt
find 명령은 표현식( expression ) 으로 구성됩니다.
여기에는 tests, actions, operators 등이 있습니다.
-maxdepth
-mindepth
같은 것은 따로 global options 라고 합니다.
tests
-name '*.sh'
, -type f
, -mtime -1
, -size +1M
. . . 같은 표현식이 test 에 해당합니다.
actions
-print
, -prune
, -delete
, -exec
, -ls
, -quit
. . . 등은 action 에 해당합니다.
operators
우선순위가 높은 순서부터입니다.
( . . . )
-not
,!
-and
,-or
또는-a
,-o
( 우선순위는 -and 가 높습니다 )
tests 와 actions 은 참, 거짓을 반환하므로 -and
, -or
연산자를 이용해 연결할 수 있습니다.
# index.html 파일에 대해 -type d 테스트는 거짓이므로 값이 표시되지 않는다.
$ find index.html -type d -and -name '*.html'
$ find index.html -type f -and -name '*.html' # -type f 로 변경
index.html
# index.html 파일에 대해 -exec test -d {} \; 액션은 비정상 종료 상태 값을 반환하므로
# 뒤이어지는 -exec echo {} \; 는 실행되지 않는다.
$ find index.html -exec test -d {} \; -and -exec echo {} \;
$ find index.html -exec test -f {} \; -and -exec echo {} \; # test -f 로 변경
index.html
기본적으로 -and
연산자는 생략해서 사용할 수 있습니다.
$ find index.html -type f -name '*.html'
index.html
$ find index.html -type d -name '*.html' # -type d
$
# -or 연산자는 생략할 수 없습니다.
$ find index.html -type d -o -name '*.html'
index.html
test 에는 하나 이상의 action 을 붙여 사용할 수 있습니다.
test 에는 출력을 위해 기본적으로 -print
액션이 적용됩니다.
따라서 다음 두개로 구성된 명령들은 서로 같은 것입니다.
$ find * -name '*.html'
$ find * -name '*.html' -print
$ find index.html -type d -o -name '*.html'
index.html
$ find index.html -type d -print -o -name '*.html' -print
index.html
$ find -path ./.git -prune
./.git
$ find -path ./.git -prune -print
./.git
하지만 다음과 같이 test 에 직접 -prune
을 제외한 action 이 사용되면
다른 test 에는 디폴트로 -print 가 적용되지 않게 됩니다.
# -name '*.txt' 테스트에 직접 -print 액션이 사용되어
# -name '*.html' 테스트에는 -print 가 디폴트로 적용되지 않는다.
$ find * -name '*.html' -o -name '*.txt' -print
dir_1/foo.txt
dir_2/dir_3/bar_2.txt
dir_2/bar_1.txt
index.txt
# -name '*.txt' 에는 -print 가 적용되지 않는다.
$ find * -name '*.html' -print -o -name '*.txt'
dir_1/foo.html
dir_2/dir_3/bar_2.html
dir_2/bar_1.html
index.html
# find * -name '*.html' -o -name '*.txt' 와 같은 것임
$ find * -name '*.html' -print -o -name '*.txt' -print
dir_1/foo.html
dir_1/foo.txt
dir_2/dir_3/bar_2.html
dir_2/dir_3/bar_2.txt
dir_2/bar_1.html
dir_2/bar_1.txt
index.html
index.txt
-prune
액션은 특정 디렉토리를 검색에서 잘라낼 때 사용합니다.
이때 뒤이어지는 테스트가 실행되려면 -or
연산자를 사용해야합니다.
# -path 테스트는 대부분 매칭이안돼 false 가되므로 and 연산은 뒤이어지는 -name 이 실행되지 않는다.
$ find -path ./.git -prune -name '*.html'
$
# -path 테스트가 성공했을 때만 -name 테스트가 실행된다.
# ( find 에서 사용되는 '*' glob 문자는 기본적으로 '.' 파일도 매칭됩니다. )
$ find -path ./.git -prune -name '*'
./.git
명령을 작성할 때 주의할 점은 다음 첫번째 명령과 같이 작성하게 되면
이것은 두번째 명령과 같게되므로 출력에 ./.git
이 남게 됩니다.
따라서 세번째와 같이 작성해야 ./.git
이 포함되는 것을 방지할 수 있습니다.
$ find -path ./.git -prune -o -name '*.html'
./dir_1/foo.html
./.git <---- ./.git 이 포함된다.
./dir_2/dir_3/bar_2.html
./dir_2/bar_1.html
./index.html
# 이것은 위 명령과 같은 것임
$ find -path ./.git -prune -print -o -name '*.html' -print
# 다음과 같이 작성해야 -prune -print 가 되지 않는다.
$ find -path ./.git -prune -o -name '*.html' -print
./dir_1/foo.html
./dir_2/dir_3/bar_2.html <---- ./.git 이 제거 되었다.
./dir_2/bar_1.html
./index.html
( . . . ) 연산자의 사용
( )
연산자는 우선순위를 조절하는 용도 외에 중복방지용으로도 사용됩니다.
$ find -path '*/.git' -prune -o -path ./dir_1 -prune -o -name '*.html' -print
./dir_2/dir_3/bar_2.html
./dir_2/bar_1.html
./index.html
# 중복되는 -prune 액션을 ( ) 을 이용해 한번만 사용할 수 있습니다.
$ find \( -path '*/.git' -o -path ./dir_1 \) -prune -o -name '*.html' -print
./dir_2/dir_3/bar_2.html
./dir_2/bar_1.html
./index.html
# -print0 액션을 두개의 -name 테스트에 모두 적용
$ find \( -name '*.txt' -o -name '*.html' \) -print0
$ find \( -name '*.txt' -o -name '*.html' \) -printf '%P\0' # \0 NUL 문자
$ find \( -name '*.txt' -o -name '*.html' \) -printf '%P\n' # \n newline
time 테스트와 +n, -n, n 숫자 값의 사용
+n
은 greater thann
-n
은 less thann
n
은 exactlyn
-mtime
, -mmin
... 에 설정한 값은 기본적으로 현재 시간으로부터 계산을 합니다.
그러므로 -mmin -60
은 현재 시간으로부터 60 분 이내에 수정된 파일을 말하고
-mtime -1
는 현재 시간으로부터 1 일 이내 ( 24 시간 이내 ) 수정된 파일들을 말합니다.
따라서 현재 시간이 15 시 일경우 어제 17 시에 수정한 파일은 검색에 포함되지만
13 시에 수정한 파일은 포함되지 않게 됩니다.
만약에 시간 계산을 현재 시간으로부터가 아닌 from the beginning of today 부터
하려면 -daystart
옵션을 사용합니다.
다음은 현재 시각으로부터 수정한지 60 분 이내의 파일들을 검색하는 명령입니다.
# 1. -prune : dir_1 과 dir_3 는 잘라내고
# 2. -type f : 디렉토리는 제외하고 일반 파일만
# 3. -mmin -60 : 현재 시각으로부터 수정한지 60 분 이내의 파일만
$ find * \( -path dir_1 -o -path dir_3 \) -prune -o -type f -mmin -60 -exec ls {} \;
dir_2/bar_1.html
dir_2/bar_1.txt
index.html
index.txt
# 수정한지 60 분이 지난 파일들
-mmin +60
# 수정한지 3 일 이내의 파일들
-mtime -3
# 수정한지 3 일이 지난 파일들
-mtime +3
# 수정한지 3 일째 되는 파일들만
-mtime 2
# 수정한지 1 일 이내의 파일들
-mtime -1 과 -mtime 0 은 같은 결과
------------------------------------------------------------
$ date # 현재 11 일 12 시
Mon Jun 11 12:38:32 KST 2018
# -mtime -1 ( 현재 시간으로 부터 1 일 이내 파일 )
# 현재 시간으로부터 계산을 하므로 날짜가 Jun 10 인 파일도 보인다.
$ find * -type f -mtime -1 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6572529 12 -rw-rw-r-- 1 mug896 mug896 8212 Jun 11 12:42 find.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime 0 ( 현재 시간으로부터 1 일째 되는 파일. 위와 같은 결과 )
$ find * -type f -mtime 0 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6572529 12 -rw-rw-r-- 1 mug896 mug896 8212 Jun 11 12:42 find.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime -3 ( 현재 시간으로부터 3 일 이내 파일 )
# 뒤에 나오는 exit_status.md 파일은 같은 Jun 8 이지만 여기에 추가되지 않는다.
$ find * -type f -mtime -3 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6560999 12 -rw-rw-r-- 1 mug896 mug896 8458 Jun 11 12:47 find.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6570224 8 -rw-rw-r-- 1 mug896 mug896 7430 Jun 8 18:25 keyword_commands.md <-- 추가
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
6570196 12 -rw-rw-r-- 1 mug896 mug896 10343 Jun 8 18:20 test.md <-- 추가
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime -4 ( 현재 시간으로부터 4 일 이내 파일 )
$ find * -type f -mtime -4 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6572535 8 -rw-rw-r-- 1 mug896 mug896 7212 Jun 8 12:35 exit_status.md <-- 추가
6560999 12 -rw-rw-r-- 1 mug896 mug896 8458 Jun 11 12:47 find.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6570224 8 -rw-rw-r-- 1 mug896 mug896 7430 Jun 8 18:25 keyword_commands.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
6570196 12 -rw-rw-r-- 1 mug896 mug896 10343 Jun 8 18:20 test.md
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime 2 ( 현재 시간으로부터 3 일째 되는 파일 )
# exit_status.md 파일은 같은 Jun 8 이지만 여기에 포함되지 않는다.
$ find * -type f -mtime 2 -ls
6570224 8 -rw-rw-r-- 1 mug896 mug896 7430 Jun 8 18:25 keyword_commands.md
6570196 12 -rw-rw-r-- 1 mug896 mug896 10343 Jun 8 18:20 test.md
# -mtime 3 ( 현재 시간으로부터 4 일째 되는 파일 )
$ find * -type f -mtime 3 -ls
6572535 8 -rw-rw-r-- 1 mug896 mug896 7212 Jun 8 12:35 exit_status.md
-daystart
옵션을 사용하게 되면 날짜를 from the beginning of today 부터 계산을 하므로
파일의 날짜가 정확히 해당일에 매칭 되는 파일들이 출력됩니다.
$ date # 현재 11 일 12 시
Mon Jun 11 12:38:32 KST 2018
# -mtime -1 ( 1 일 이내 파일 )
# 정확히 날짜가 Jun 11 인 파일만 출력되고 Jun 10 인 파일들은 포함되지 않는다.
$ find * -daystart -type f -mtime -1 -ls
6560999 12 -rw-rw-r-- 1 mug896 mug896 9458 Jun 11 13:31 find.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
# -mtime -2 ( 2 일 이내 파일 )
# 2 일 이내 이므로 Jun 10, 11 파일들이 출력된다.
$ find * -daystart -type f -mtime -2 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6560999 12 -rw-rw-r-- 1 mug896 mug896 9458 Jun 11 13:31 find.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime 0 ( 1 일째 되는 파일 )
# 날짜가 Jun 10 인 파일들은 포함되지 않는다.
$ find * -daystart -type f -mtime 0 -ls
6560999 12 -rw-rw-r-- 1 mug896 mug896 9458 Jun 11 13:31 find.md
6572864 4 -rw-rw-r-- 1 mug896 mug896 2703 Jun 11 08:28 SUMMARY.md
# -mtime 1 ( 2 일째 되는 파일 )
# 정확히 날짜가 Jun 10 인 파일들만 출력된다.
$ find * -daystart -type f -mtime 1 -ls
6572539 8 -rw-rw-r-- 1 mug896 mug896 7757 Jun 10 13:36 eval.md
6571730 16 -rw-rw-r-- 1 mug896 mug896 15779 Jun 10 13:37 here_document.md
6572862 12 -rw-rw-r-- 1 mug896 mug896 8902 Jun 10 15:30 test_operators.md
# -mtime 3 ( 4 일째 되는 파일 )
# exit_status.md 파일을 포함해서 날짜가 Jun 8 인 파일들이 출력된다.
$ find * -daystart -type f -mtime 3 -ls
6572535 8 -rw-rw-r-- 1 mug896 mug896 7212 Jun 8 12:35 exit_status.md
6570224 8 -rw-rw-r-- 1 mug896 mug896 7430 Jun 8 18:25 keyword_commands.md
6570196 12 -rw-rw-r-- 1 mug896 mug896 10343 Jun 8 18:20 test.md
size 테스트와 +n, -n, n 숫자 값의 사용
+n
은 greater thann
-n
은 less thann
n
은 exactlyn
Suffix | Description |
---|---|
b | for 512-byte blocks (suffix 를 사용하지 않을 경우 default 값) |
c | for bytes |
w | for two-byte words |
k | for Kibibytes (KiB, units of 1024 bytes) |
M | for Mebibytes (MiB, units of 1024 * 1024 = 1048576 bytes) |
G | for Gibibytes (GiB, units of 1024 * 1024 * 1024 = 1073741824 bytes) |
greater than
# greater than 1 Kibibytes
$ find /usr/bin -size +1k -exec stat -c "%s %n" {} + | sort -n | head -3
1039 /usr/bin/aptdcon
1057 /usr/bin/dh_python2
1062 /usr/bin/crc32
# greater than 2 Kibibytes
$ find /usr/bin -size +2k -exec stat -c "%s %n" {} + | sort -n | head -3
2060 /usr/bin/editdiff
2068 /usr/bin/apport-unpack
2072 /usr/bin/ppmquantall
# greater than 1 Mebibytes
$ find /usr/bin -size +1M -exec stat -c "%s %n" {} + | sort -n | head -3
1066448 /usr/bin/gthumb
1066992 /usr/bin/gpg
1120400 /usr/bin/arm-none-eabi-objcopy
# greater than 2 Mebibytes
$ find /usr/bin -size +2M -exec stat -c "%s %n" {} + | sort -n | head -3
2162296 /usr/bin/mpv
2172376 /usr/bin/busybox
2312584 /usr/bin/x86_64-linux-gnu-ld.gold
less than
less than 은 사용 시 주의할 점이 하나 있는데 먼저 숫자 값에서 -1 을 해야 한다는 것입니다. 그러니까 1M 보다 작은 크기의 파일은 -1M 가 아니라 -2M 로 적어야 되고 5k 보다 작은 파일은 -5k 가 아니라 -6k 로 적어야 합니다.
# 0 Kibibytes 이하가 되므로 아무것도 표시되지 않는다.
$ find /usr/bin -size -1k -exec stat -c "%s %n" {} + | sort -rn | head -3
$
# 1 Kibibytes 이하가 된다.
$ find /usr/bin -size -2k -exec stat -c "%s %n" {} + | sort -rn | head -3
1007 /usr/bin/dvipdf
1003 /usr/bin/spd-conf
998 /usr/bin/preparetips5
# 2 Kibibytes 이하가 된다.
$ find /usr/bin -size -3k -exec stat -c "%s %n" {} + | sort -rn | head -3
2044 /usr/bin/aspell-import
2039 /usr/bin/pa-info
1984 /usr/bin/zcat
# 0 Mebibytes 이하가 되므로 아무것도 표시되지 않는다.
$ find /usr/bin -size -1M -exec stat -c "%s %n" {} + | sort -rn | head -3
$
# 1 Mebibytes 이하가 된다.
$ find /usr/bin -size -2M -exec stat -c "%s %n" {} + | sort -rn | head -3
1039920 /usr/bin/arm-none-eabi-gprof
1027064 /usr/bin/nm-connection-editor
1001688 /usr/bin/arm-none-eabi-ranlib
# 2 Mebibytes 이하가 된다.
$ find /usr/bin -size -3M -exec stat -c "%s %n" {} + | sort -rn | head -3
2046584 /usr/bin/x86_64-linux-gnu-dwp
2038608 /usr/bin/qalculate-gtk
1997016 /usr/bin/qemu-img
exact
suffix 를 사용하지 않을 경우 default 는 b
이므로 exact 사이즈는 c
suffix 를 사용합니다.
$ find /usr/bin -size 97496c -ls
7209485 96 -rwxr-xr-x 1 root root 97496 Dec 14 2019 /usr/bin/gzip
디렉토리가 symbolic link 일 경우
find 명령에 사용되는 디렉토리가 symbolic link 일 경우
마지막에 /
를 붙여서 디렉토리임을 나타내야 합니다.
# ubuntu 20.04 의 경우 /bin 가 /usr/bin 로 symbolic link 되어있어 정상적으로 실행되지 않는다.
$ find /bin -size -3M -exec stat -c "%s %n" {} + | sort -rn | head -3
7 /bin
# 이때는 다음과 같이 /bin 마지막에 '/' 를 붙여주어야 합니다.
$ find /bin/ -size -3M -exec stat -c "%s %n" {} + | sort -rn | head -3
2046584 /bin/x86_64-linux-gnu-dwp
2038608 /bin/qalculate-gtk
1997016 /bin/qemu-img
ls
명령도 마찬가지
$ ls /bin
/bin@
$ ls /bin/
X11@ lxc*
2to3-2.7* lxd*
FileCheck-12@ lynx*
. . .
find 외 다른 명령
find 명령이 검색을 위한 다양한 옵션을 제공하기는 하지만 실제 자주 사용하는데 있어서
불편한 점이 있습니다. 이번에 소개해 드릴 fd
명령은 사용자 친환적으로 좀더 쉽게
사용할 수 있게 만들어졌고 기본적으로 검색 패턴에 regex 을 사용합니다.
앞서 grep 명령 페이지에서 소개했던 ripgrep 명령과 마찬가지로 multi-thread 를 활용하는
rust 언어로 작성되어 속도가 아주 빠릅니다.
Quiz
stat
명령을 이용하면 file 이나 directory 의 상태 정보를 조회해 볼 수 있습니다.
여기에는 Access time, Modify time, Change time 정보가 있는데요.
각각 어떤 경우에 변경이 될까요?
$ stat foo.sh
File: foo.sh
Size: 215 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 11277303 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ mug896) Gid: ( 1000/ mug896)
Access: 2019-04-15 19:21:25.540166670 +0900
Modify: 2019-04-15 19:21:25.540166670 +0900
Change: 2019-04-15 19:21:25.540166670 +0900
Birth: -
Access time ( atime )
- file : cat, more 같은 명령으로 내용을 읽었을 때
- directory : ls 명령으로 디렉토리 내용을 읽었을 때
atime 은 효율성을 위해 매번 바뀌지 않고 mtime 이나 ctime 보다 old 할 경우만 변경됩니다.
Modify time ( mtime )
- file : 파일 내용이 수정되었을 때 ( echo hello >> foo.sh )
- directory : 디렉토리 에서 파일이 create, delete, rename 되어 목록이 변경되었을 때
( 파일 내용이 수정되는 경우는 포함되지 않음 )
Change time ( ctime )
change time 은 파일 내용을 말하는 것이 아니고 파일이름, access 모드, uid, gid 같은 상태 정보를 말합니다. 그러니까 rename 하거나 chmod, chown 같은 명령을 사용하게 되면 변경되겠죠. 또한 파일 내용이 수정될 경우 size 정보가 변경되므로 ctime 도 함께 변경되게 됩니다.
touch
명령은 atime, mtime, ctime 모두를 한번에 최신으로 변경합니다.
2.
find 명령으로 검색한 파일들을 디렉토리 구조를 유지하면서 다른 디렉토리로 copy 하려면 어떻게 할까요?
cpio
( copy in, copy out ) 명령은 tar
( tape archive ) 명령 이전에 백업에 사용되던 툴인데요.
입력으로 파일 리스트를 받아서 해당 파일들을 모두 연결하여 하나의 스트림으로 보냅니다.
따라서 백업할 때 디스크가 다 차면 다음 디스크를 넣으라는 문구가 출력되면서 백업이 진행됩니다.
지금은 tar
가 더 편리한 기능을 많이 제공하기 때문에 주로 사용되지만
다음과 같이 검색한 파일들을 디렉토리 구조를 유지하면서 copy 할때는 cpio
명령이
유용하게 사용됩니다.
# -p : pass-through 모드로 입력받은 파일들을 바로 디렉토리로 copy 합니다.
# -d : 필요하면 디렉토리를 생성
# -m : preserve-modification-time
# -v : verbose
$ find -name '*.html' | cpio -pdmv /destination/dir
------------------------------------------------------
# -o : copy-out 모드로 stdout 스트림으로 출력합니다.
$ find -name '*.html' | cpio -ov > html_only.cpio
# -H : tar 파일 형식으로 출력합니다.
$ find -name '*.html' | cpio -ov -H tar > html_only.tar
# -i : copy-in 모드로 stdin 스트림으로부터 cpio, tar 파일을 읽어들여 extract 합니다.
# -u : unconditionally 덮어쓰기
$ cpio -idmuv < html_only.cpio
------------------------------------------------------
# 검색한 '*.db' 파일 목록을 cpio 로 전달하면 해당 파일들을 연결해서 stdout 스트림으로 출력하고
# 다음 gzip 이 받아서 압축하여 stdout 로 출력하면 split 명령이 받아서 100M 크기 파일로 저장
$ find -name '*.db' | cpio -ov -H tar | gzip -c - | split -d -b 100M - tardisk
# cat 명령이 100M 크기의 tardisk00, tardisk01 ... 파일들을 하나로 합쳐서
# stdout 으로 출력하면 tar 가 stdin 으로부터 받아서 현재 디렉토리에 extract 합니다.
$ cat tardisk* | tar -xvz
# cpio 는 입력파일과 동일한 경로에 extract 됩니다. ( 파일이 /bin/gzip 이면 /bin 에 extract 됨 )
$ cat tardisk* | gzip -cd - | cpio -idmuv