![find를 사용하여 파일 이름의 특수 문자를 처리하는 방법](https://linux55.com/image/79611/find%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20%ED%8C%8C%EC%9D%BC%20%EC%9D%B4%EB%A6%84%EC%9D%98%20%ED%8A%B9%EC%88%98%20%EB%AC%B8%EC%9E%90%EB%A5%BC%20%EC%B2%98%EB%A6%AC%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95.png)
다음과 같은 특정 문자로 시작하는 모든 파일을 찾고 싶습니다.
find . -maxdepth 1 \( -name "^m*" -a ! -name "g$" \) -print
하지만 누군가 이름에 특수 문자가 포함된 파일을 생성한다면 어떻게 될까요? 예를 들어
touch "
marst"
표준을 충족하더라도 감지되지 않습니다. 공백으로 시작하는 파일을 찾으려면 코드를 어떻게 변경해야 합니까?
또한 \( -name "^m*" -a ! -name "g$" \)
find의 파일이 "marr"이 아니라 "./marr"이기 때문에 작동하지 않습니다. 이는 아무것도 찾을 수 없음을 의미합니다. 단어의 시작 부분과 일치하도록 코드를 어떻게 변경할 수 있나요?
답변1
-name
항상 이름만 일치합니다. 즉, 경로와 일치하지 않습니다.모두이름. 해당 값은 정규 표현식이 아닌 패턴이므로 다음 m
을 사용하여 시작하는 파일 이름을 찾을 수 있습니다.
-name 'm*'
g
그리고 다음으로 끝나는 이름
-name '*g'
정규식을 사용하려면 -regex
옵션을 참조하세요.
답변2
개행 문자로 시작하거나 그 뒤에 오는 파일 이름을 일치시키려면 m
다음과 같습니다.
NL='
'
find . \( -name 'm*' -o -name "*${NL}m*" \) -print
적어도 GNU의 경우 find
유효한 *
문자 시퀀스를 형성하지 않는 바이트 시퀀스는 일치하지 않습니다. 이것이 잠재적인 문제라면 C 로케일을 사용하는 것이 더 나을 것입니다.
LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print
예:
$ touch mom $'two\nminutes' $'mad\x80'
$ find . -name 'm*'
./mom
$ find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./two?minutes
./mom
$ LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) -print
./mad?
./two?minutes
./mom
다음 으로 시작 m
하지만 끝나지 않는 줄을 포함하는 파일 이름의 경우 g
:
LC_ALL=C find . \( -name 'm*' -o -name "*${NL}m*" \) ! \(
-name '*g' -o -name "*g${NL}*" \) -print
일부 find
구현에는 파일 일치에 대한 비표준 옵션이 있습니다.길(보통은 그렇지 않다.이름) 정규식을 사용하지만 구현에 따라 동작이 다르므로 여기서는 필요하지 않습니다.
m
예를 들어, 정규 표현식이 필요한 곳은 이름이 어떤 것으로 끝나는 줄로 시작하지 않는 파일을 찾는 것입니다 g
(예: nor $'cat\nman\ndog'
는 아님 ).$'plate\nmug\ncup'
$'cat\nman\nmug'
GNU 사용 find
:
LC_ALL=C find . -regextype posix-extended -regex \
".*/(([^m$NL/][^/$NL]*|m[^/$NL]*[^$NL/g]|m|)($NL|\$))*"
m
또는 이름이 다음과 같이 시작하고 끝나지 않는 줄이 하나 이상 있는 파일 g
( 과 유사 $'mad\nmug'
하지만 아님 $'ming\nmong'
):
LC_ALL=C find . -regextype posix-extended -regex \
".*/([^/]*$NL)?m([^$NL/]*[^g$NL/])?(\$|${NL}[^/]*)"
답변3
이 -regex
플래그를 사용하여 glob에서 제공하는 더 복잡한 일치가 필요한지 확인할 수 있습니다. 전체 경로와 일치하므로 파일 이름 부분만 일치시키려면 다음과 같이 할 수 있습니다.
find . -maxdepth 1 -regex '/[
]?m[^/]*[^g]$' -print
참고하시기 바랍니다이 답변개행 문자를 일치시키는 데 사용할 수 없으므로 \n
요청했기 때문에 문자 클래스에 공백이 있는 개행 문자를 넣습니다.
답변4
^
find에서는 the 또는 the를 $
단순한 이름으로 사용할 필요가 없습니다 .
용도 찾기모델이름을 위해. 패턴은 다음과 같습니다.
- 전체 이름과 일치합니다. 처음부터 끝까지. 언제나.
- find는 이 패턴을 사용하기 전에 찾은 모든 파일의 경로를 제거합니다.
- 유일한 특수 문자는
*
?
and[ ]
(^ 또는 $ 아님)입니다.
m
따라서 및로 시작하는 파일을 일치시키려면아니요다음으로 끝납니다 g
:
find . -maxdepth 1 -name 'm*[!g]' -o -name 'm'
'm'
파일에 문자가 하나만 있는 경우를 다룹니다 .
그러나 생성한 파일 touch $'\nmarst'
(예, bash에서와 같이 개행을 작성할 수 있습니다)은 new-line 으로 시작하지 않고 m
new-line 으로 시작합니다 $'\n'
. 단순 모드에서는 대체할 수 있는 방법이 없지만 -o
find의 OR( ) 옵션을 사용할 수 있습니다.
find . -maxdepth 1 \( -name 'm*' -o -name $'\n'"m*" \) -a ! -name '*g'
요구사항이 길어지면 이는 어려워집니다.
매우 복잡한 문자열의 경우 -regex
find 옵션을 사용할 수 있습니다.