제외 파일에 나열된 경로를 찾는 명령

제외 파일에 나열된 경로를 찾는 명령

명령에서 여러 경로를 제외해야 합니다 find. 예를 들어:

find "$(pwd)" -not \( \
 -path "*/.git"\
 -o -path "*/.git/*"\
 -o -path "*/.vscode"\
 -o -path "*/.vscode/*"\
 -o -path "*/node_modules"\
 -o -path "*/node_modules/*"\
 -o -path "*/Image"\
 -o -path "*/Image/*"\
 -o -path "*/Rendered"\
 -o -path "*/Rendered/*"\
 -o -path "*/iNotebook"\
 -o -path "*/iNotebook/*"\
 -o -path "*/GeneratedTest"\
 -o -path "*/GeneratedTest/*"\
 -o -path "*/GeneratedOutput"\
 -o -path "*/GeneratedOutput/*"\
 -o -path "*/*_files" \) -type d

그러나 명령줄에 경로를 모두 나열하는 대신 텍스트 파일에서 이러한 경로를 읽고 싶습니다. 어떻게 해야 하나요?

답변1

나중에 호출에 사용할 배열을 구성합니다 find. 다음 스크립트는 표준 입력에서 개행으로 구분된 경로 패턴을 읽고 다음을 호출합니다 find.

#!/bin/sh

set --

while IFS= read -r path; do
    set -- "$@" -o -path "$path"
done

shift   # remove initial "-o" from $@

find . -type d ! '(' "$@" ')'

당신은 이것을 실행할 것입니다

./script.sh <paths.txt

어디 paths.txt처럼 보일까요?

*/.git
*/.git/*
*/.vscode
*/.vscode/*
*/node_modules
*/node_modules/*
*/Image
*/Image/*
*/Rendered
*/Rendered/*
*/iNotebook
*/iNotebook/*
*/GeneratedTest
*/GeneratedTest/*
*/GeneratedOutput
*/GeneratedOutput/*
*/*_files

또는 경로 패턴은 기본적으로 디렉터리 이름이므로 다음과 같습니다.

#!/bin/sh

set --

while IFS= read -r dirname; do
    set -- "$@" -o '(' -name "$dirname" -prune ')'
done

shift   # remove initial "-o" from $@

find . -type d ! '(' "$@" ')'

스키마 파일에는 다음이 포함됩니다.

.git
.vscode
node_modules
Image
Rendered
iNotebook
GeneratedTest
GeneratedOutput
*_files

이 코드 변형은 find파일의 패턴과 일치하는 디렉터리로 내려가는 것을 중지하는 반면, 첫 번째 스크립트(및 코드)는 -path해당 경로에 관심이 없는지 여부에 관계없이 제외된 디렉터리의 모든 항목에 대해 패턴을 테스트합니다. 다음 중 하나에 관심이 있습니다.

답변2

grep및 를 사용하여 경로 목록(정규식 또는 고정 문자열)을 기반으로 파일을 필터링 find할 수 있습니다. -exec예제를 조정하여 pathsinclude라는 파일을 만듭니다.

/.git$
/.git/
/.vscode$
/.vscode/
/node_modules$
/node_modules/
/Image$
/Image/
/Rendered$
/Rendered/
/iNotebook$
/iNotebook/
/GeneratedTest$
/GeneratedTest/
/GeneratedOutput$
/GeneratedOutput/
/.*_files$

그런 다음 실행

find /your/search/path -type d ! -exec sh -c "echo {} | grep -q -f paths" \; -print

이는 아래의 디렉터리를 찾고 , 찾은 각 디렉터리에 대해 의 패턴과 일치하는지 /your/search/path확인하는 데 사용됩니다 . 그렇지 않은 경우 인쇄하십시오. 이는 확장을 위한 기반으로 사용됩니다. 파일의 패턴과 일치하지 않는 디렉터리 경로에만 관심이 있는 경우greppaths그리고여러 줄을 포함하는 경로가 없으면 grep단일 호출로 출력을 사후 처리할 수 있습니다.

find /your/search/path -type d | grep -v -f paths

실제로 일부 경로에 전혀 관심이 없는 경우(패턴은 항상 디렉터리 이름과 일치하고 해당 디렉터리 아래의 모든 항목과 일치합니다. 정리를 통해 작업을 더 간단하게 만들 수 있습니다.

find /your/search/path -type d \( -exec sh -c "echo {} | grep -q -f paths" \; -prune -o -print \)

경로에는 다음이 포함됩니다.

/.git$
/.vscode$
/node_modules$
/Image$
/Rendered$
/iNotebook$
/GeneratedTest$
/GeneratedOutput$
/.*_files$

답변3

당신이 할 수 있는 일은 빌드 명령을 사용 awk하고 find이를 "래퍼" 스크립트 또는 쉘 함수의 변수로 전달하는 것입니다.

p=$( awk '{printf "-not -path %s ",$0}' "$1" )
find "$PWD"  $p -type d

참조 경로 목록이 있는 ./find_wrapper.sh paths.txt곳에서 이를 호출합니다 .path.txt

'*/.git'
'*/.git/*'
'*/.vscode'
'*/.vscode/*'
'*/node_modules'
'*/node_modules/*'
'*/Image'
...

왜이 짓을 했나요? 전체 줄을 작성하는 이유 awk는 스크립트에서 이를 수행할 이유가 없기 때문입니다. \줄 연속은 명령을 보다 체계적으로 보이게 하기 위해 존재하지만 기능적으로는 아무런 이점도 제공하지 않습니다. $p여기서는 실제로 단어 분할을 수행하고 싶기 때문에 인용하지 않았습니다. 그렇지 않으면 find별도의 플래그와 매개변수가 아닌 하나의 거대한 문자열로 처리합니다. 작은 따옴표의 경우글로벌을 피하기 위해큰따옴표 안에 효과가 있습니다.

아니면 파이프라인으로

awk '{printf "-not -path %s ",$0}' "$1" | xargs -L 1  find "$PWD" -type d 

관련 정보