find -perm 정리.

** 글이 길어졌고, 쓰다가 보니 또 새로운 사실을 알게되어, 맨 처음 쓰려고했던 내용과 조금은 다른 방향으로 나가게 됐다.

여기서 기억해야할 사항은 한가지다. Write Permission 을 찾기 위해선 6(RW)이 아니고, 2(W)를 써야 한다. 이에 관한 얘기는 아래 쪽에 써놨다.


딴 거 하다가, 갑자기 find -perm 이 눈에 밟혔다. 대충 정리를 하고 넘기려 했는데.. 강한 벽에 부딪혀 버렸다.

하여.. 조금 더 시간을 내서 가능한한 확실하게 정리를 해보려고 한다.
늘 그렇지만, man page 에 나와있는 영어 설명만으로 이해를 하기엔, 내 독해 실력이 너무나도 떨어지기에.. 이런 저런 꽃삽질을 통해 작동 방식을 알아낸 뒤, 그에 근거해 역으로 영문자 설명을 해독(?)하는 형식을 취할 수 밖에 없었다.

일단, Man Page 에 나와있는 내용을 그대로 옮겨본다.

-perm mode
File’s permission bits are exactly mode (octal or symbolic). Since an exact match is required, if you want to use this form for symbolic modes, you may have to specify a rather complex mode string. For example -perm g=w' will only match files which have mode 0020 (that is, ones for which group write permission is the only permission set). It is more likely that you will want to use the/’ or -' forms, for example-perm -g=w’, which matches any file with group write permission.

-perm -mode
All of the permission bits mode are set for the file. Symbolic modes are accepted in this form, and this is usually the way in which you would want to use them. You must specify u',g’ or `o’ if you use a symbolic mode.

-perm /mode
Any of the permission bits mode are set for the file. Symbolic modes are accepted in this form. You must specify u',g’ or `o’ if you use a symbolic mode. If no permission bits in mode are set, this test matches any file (the idea here is to be consistent with the behaviour of -perm -000).

-perm 뒤에 쓰일 수 있는 선택사항은 이처럼 총 세가지다.
아무 기호 없이 쓰거나, – 또는 / 를 붙인다. 예전엔 + 도 있었나본데, 2005년 이후론 사용하지 않는다고 한다.

각 mode 뒤에는 권한을 표시할 문구가 오는데, 숫자 8진수 값도 되고, 권한 상징문자(ugoa/rw)도 쓸 수 있다. 각각 상황에 따라, 숫자 또는 문자를 쓰게 된다. (ugoa 는 각각 User, Group, Others, All 을 뜻한다.)

mode : 부호없이 권한만 표기

-perm 770 등으로 쓸 수 있는데, 이 경우는 정확히 그 허가권이 설정된 파일만 찾는다. 따라서 8진수 숫자 표기가 잘 어울리고(?), 권한문자를 쓰려면 조금 복잡한 방식을 써야만 한다. 따라서, 딱 그! Permission 만을 찾을 때 이 방식을 쓰면 된다. (가장 이해하기 쉽고, 간단하다.)

-mode : -를 먼저 쓰고 뒤에 권한 표기

‘-‘ 가 빼기 기호인지, 그냥 줄표인지는 알 수가 없다. 따라서 기호만으로 그 의미를 짐작하기는 거의 불가능하다.
아무튼, 설명에는 ‘All of(-)‘ 와 ‘Any of(/)‘ 로 구분되어 있다.

All 과 Any 의 차이는 뭘까? Man Page 에 정확하게 설명되어 있다고 볼 수도 있지만, 결과로 유추해보면,

  • -mode : All – U/G/O 조건 간 AND 연산. U/G/O 의 조건을 동시에/모두(All) 만족해야함.
  • /mode : Any – U/G/O 조건 간 OR 연산. U/G/O 중 어느 한 조건만(Any) 만족해도 됨.

이렇게 생각해볼 수 있겠다.

….

이제부터 좀 헷갈리는데.. 잘 정리될 수 있으려나 모르겠다.
눈으로 확인하기 위해서, 다음과 같은 파일을 만들었다.

 ls -al
-rw-rw-rw- 1 russo russo   0 2020-12-03 00:26 test1
-rw-rw-r-x 1 russo russo   0 2020-12-03 17:35 test2
-r--r--r-- 1 russo russo   0 2020-12-03 17:35 test3
-r--r----- 1 russo russo   0 2020-12-03 17:36 test4
-rw-r----- 1 russo russo   0 2020-12-03 17:36 test5
-rw-r--r-- 1 russo russo   0 2020-12-03 17:36 test6

그리고, 이 상태에서 다음과 같이 find 명령을 내렸다. -perm xxx 이후 명령(-type 과 stat)은, 결과를 알아보기 쉽게 하기 위하여 덧붙였다.

find . -perm -666 -type f -exec stat -c "%a %n" {} +
666 ./test1

여기는 어려운게 전혀 없다. 이 상황은 -perm 666 과 100% 동일하다.
그러나, 다음 명령은 조금 생각했던 바와는 다른 결과를 보여준다.

find . -perm -220 -type f -exec stat -c "%a %n" {} +                                                                                                
666 ./test1
665 ./test2

-perm -220 은, ‘User/Group 은 Write 권한, Other 는 권한 관계없음’을 뜻한다.

그리고, 가장 중요한 한가지. ‘-‘ 에는 각 개체(U/G/O)간 ‘AND’ 조건이 성립된다. 따라서, ‘User 가 2 권한을 갖고, 동시에 Group 이 2 권한을 갖는 파일을 찾으라’는 명제가 된다.

권한 2 는 write 이므로, 실제로는 6(4+2) 을 뜻하는데, User 와 Group 모두 6을 만족시키는 파일은 test1 과 test2 밖에 없다.

그러면 이번엔 같은 명령을 / 로 내려보면 어떨까?

find . -perm /220 -type f -exec stat -c "%a %n" {} +
666 ./test1
665 ./test2
640 ./test5
644 ./test6

-perm /220 은 User 또는 Group 어느 쪽이든 권한 2, 즉 6을 갖는 모든 파일을 뜻하고 있으므로, test1, test2, test5, test6 이 선택됐다.

/mode : / 를 앞에 쓰고 뒤에 권한을 덧붙임

/mode 는 위에서 이미 설명을 해버렸기에, 여기선 더 할 말이 없네?
다시 정리하면, -mode 는 UGO 간 AND, /mode 는 OR 연산이다!


그런데, NOT 연산을 할 때는..?? find 에서 NOT 은 ! 을 붙이면 되므로, 명령 형식은 다음과 같다.

find . ! -perm -111                                 
./test1
./test2
./test3
./test4
./test5
./test6

find . ! -perm /111
./test1
./test3
./test4
./test5
./test6

어떤 예제를 보면 ! 를 이스케이핑해서 \! 로 하고 있는데, 적어도 내 환경에선 그냥 느낌표만으로 잘 작동했다.

그런데.. 위 두 결과에서 test2 가 /111 에선 빠져있다.
왜?

! -perm -111 을 먼저 풀어보면 이렇게 된다.

NOT (UX && GX && OX)
== (NOT UX) OR (NOT GX) OR (NOT OX)

AND 를 뒤집으면 OR 가 되므로, UGO 중 어느 한쪽이라도 실행권한이 없으면 검색에 걸리게 된다. test2 는 Others 에게만 실행권한이 있으므로(실제론 이럴 일이 없지만), 검색 결과에 포함되었다.

! -perm /111 은 이렇다.

NOT (UX OR GX OR OX)
== (NOT UX) AND (NOT GX) AND (NOT OX)

이 경우는 U/G/O 어느 한 쪽이라도 실행권한이 있으면 선택되지 못한다. 즉, 모두 실행권한이 없어야만 한다. test2 는 Others 에 실행권한이 있으므로 탈락!

따라서, NOT 연산을 할 때는 – 와 / 구분을 확실히 해줘야만 하겠다.

-mode, /mode 와 8진수 권한 사용시 주의점! (2와 4는 6을 포함한다?)

-, / 없이 그냥 8진수만 사용하면, 정확히 그 허가권을 가진 파일만 찾게되니 다른 결과가 나올 가능성은 작다.
그러나 -, / 사용 시에는, 숫자가 ‘최소한’이라는 의미를 갖게 된다.

# 허가권이 440 인 파일만을 찾는다.
find . -perm 440 -type f -exec stat -c "%n %a" {} + 
./test4 440

# -440 은..?
find . -perm -440 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665
./test3 444
./test4 440
./test5 640
./test6 644

# /440 은 또 어떻게 다를지?
find . -perm /440 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665
./test3 444
./test4 440
./test5 640
./test6 644

-440 은, User / Group 모두 허가권 4(Read)를 만족하는 파일을 찾는다. 그런데, 결과에는 허가권이 6인 파일도 포함이 돼 있다.
이유는, 사실 6 이라 표시는 돼 있지만, 이건 4(R) + 2(W) 이기에, 6(RW)이 당연히 포함될 수 밖에 없다.

마찬가지로, -220 도 같은 논리가 적용되며, -660 과 결과가 같다. (리눅스 파일 권한에서, R 없이 W만 있을 수는 없기에!)

find . -perm -220 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665

find . -perm -660 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665

여기서 한가지 의문이 생긴다. Group 이 4 인 파일만을 찾아내려면 어떻게 해야 하려나?? U/O 는 어떤 권한이 있는지 관계없고, 오로지 Group 이 read only 인 파일을 찾으려면?

Group Read Only 찾기

이건 8진수 보다는 권한문자 방식을 쓰는 편이 훨씬 편하다. 또 사고를 ‘반대로’ 해야만 한다. (그냥 8진수만을 써서 해결할 수 있는 방법이 있으려나?)
즉, ‘그룹 허가권에 Write 가 포함되지 않은 것’을 찾아야 원하는 결과를 얻을 수 있다.

find . ! -perm -g+w -type f -exec stat -c "%n %a" {} +
./test3 444
./test4 440
./test5 640
./test6 644

find . ! -perm /g+w -type f -exec stat -c "%n %a" {} +
./test3 444
./test4 440
./test5 640
./test6 644

# 물론, 8진수도 가능은 하다. 6 이 아니고, 2 라는 점을 확실히 기억해야 한다.
find . ! -perm -020 -type f -exec stat -c "%n %a" {} +
./test3 444
./test4 440
./test5 640
./test6 644

find . ! -perm /020 -type f -exec stat -c "%n %a" {} +
./test3 444
./test4 440
./test5 640
./test6 644

-g+w, /g+w 두 명령 결과는 같은데, 여기서만 그런건지 확실하진 않다.

-g+w 로 했을 땐, U/O 에 대한 조건이 빠져있으므로, U/O 는 아예 판단 조건에 들지 않는다. Man page 를 참고하면 이 부분이 확실해진다.

find . -perm -220
find . -perm -g+w,u+w

Both these commands do the same thing; search for files which are writable by both their owner and their group.

Others 에 대한 언급이 전혀 없으므로, 그냥 무시한다는 뜻으로 보면 되겠다.

따라서, U/G/O 중 어느 하나만 조건을 줄 때는, – 든 / 든 관계가 없다고 보여진다.

이제, 060 과 020 의 차이에 대해 생각해봐야겠다.

060, 020??

언뜻 생각하면 060 과 020 은 같은 결과를 내줘야할 듯 하지만, 그렇질 못하다.

find . -perm /060 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665
./test3 444
./test4 440
./test5 640
./test6 644

find . -perm /020 -type f -exec stat -c "%n %a" {} +
./test1 666
./test2 665

엄밀하게 말해서 ‘쓰기’ 허가권은 2 이지 6 이 아니다. 6은 ‘읽기&쓰기’이다. (내가 뭔가 크게 착각하고 있었나보다.)

이로 미루어 유추해보건대, -perm /060 은 /040 OR /020 으로 봐야 맞다. 그래야 저런 결과가 나온다. 060 을 검색했는데 test3(444), test4(444)가 나왔다는 사실은, 040 OR 020 을 뒷받침해준다.

따라서 Group Write 허가권을 정확하게 짚어내려면 6 이 아닌 2 를 택해야 한다.

아마도, find 내부에서 이를 처리하기 위해 이진 연산을 하는 모양이다. (소스 코드를 보면 알 수야 있겠지만.. C 로 돼 있을테니 나야 봐도 모르겠지..) 그러니 6 이 아니라 4 + 2 고, 이걸 따로 따로 OR 연산처리하게끔 돼 있는 듯..?

실 사용 예

실 사용시에는 Octal 도 쓰지만, Symbolic 방식이 좀 더 눈에 잘 들어오므로, man page 에 나와있는 몇 용례를 옮겨본다.

# 아래 두 명령은 같은 결과를 보여준다.
find . -perm /u+w,g+w
find . -perm /u=w,g=w

# 아래 두 명령은 같은 결과를 보여준다.
find . -perm -444 -perm /222 \! -perm /111
find . -perm -a+r -perm /a+w \! -perm /a+x

자.. 헷갈리지 말고 잘 기억할 수 있기를.
또, 다음에 이 문서를 봐도, 도대체 뭔 소리를 써놓은거야?? 라고 하지 않기를..

아무도안아무도안
Author: 아무도안

안녕하세요. 글 남겨주셔서 고맙습니다.