스크립트의 변수를 통해 find 명령의 경로 매개변수에 '*' 와일드카드를 전달하는 방법은 무엇입니까?

스크립트의 변수를 통해 find 명령의 경로 매개변수에 '*' 와일드카드를 전달하는 방법은 무엇입니까?

find와일드카드로 제한되어 있지만 경로 이름에 공백이 있는 폴더 집합에서 파일을 찾는 데 사용하고 싶습니다 .

명령줄에서는 쉽습니다. 다음 예제는 모두 작동합니다.

find  te*/my\ files/more   -print
find  te*/'my files'/more  -print
find  te*/my' 'files/more  -print

terminal/my files/more예를 들어 및 에서 파일을 찾습니다 tepid/my files/more.

그러나 이것이 스크립트의 일부가 되어야 합니다. 내가 필요한 것은 다음과 같습니다.

SEARCH='te*/my\ files/more'
find ${SEARCH} -print

find불행하게도 내가 무엇을 하든 스크립트 내의 명령 에 와일드카드와 공백을 혼합할 수 없는 것 같습니다 . 위의 예는 다음 오류를 반환합니다(예기치 않게 백슬래시가 두 배로 늘어난 것에 주의하세요).

find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory

따옴표를 사용하려고 해도 실패합니다.

SEARCH="te*/'my files'/more"
find ${SEARCH} -print

따옴표의 의미를 무시하고 다음 오류를 반환합니다.

find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory

여기에 또 하나의 예가 있습니다.

SEARCH='te*/my files/more'
find ${SEARCH} -print

예상대로:

find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory

내가 시도한 모든 변형은 오류를 반환합니다.

너무 많은 폴더를 반환하기 때문에 잠재적으로 위험할 수 있는 해결 방법이 있습니다. 다음과 같이 모든 공백을 물음표(단일 문자 와일드카드)로 변환합니다.

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?}       # Convert every space to a question mark.
find ${SEARCH} -print

이는 다음과 같습니다.

find te*/my?files/more -print

이는 올바른 폴더뿐만 아니라 terse/myxfiles/more예상되지 않은 을 반환합니다.

내가 하려는 일을 어떻게 성취할 수 있나요? Google은 나에게 도움이 되지 않았습니다 :(

답변1

정확히 동일한 명령이 스크립트에서 제대로 작동해야 합니다.

#!/usr/bin/env bash
find  te*/my\ files/ -print

만약 너라면필요변수로 사용하려면 좀 더 복잡해집니다.

#!/usr/bin/env bash
search='te*/my\ files/'
eval find "$search" -print

경고:

이와 같이 사용하는 것은 eval안전하지 않으며 파일 이름에 특정 문자가 포함될 수 있는 경우 임의적이고 유해한 코드가 실행될 수 있습니다. 보다배쉬 FAQ 48자세한 내용은.

경로를 인수로 전달하는 것이 더 좋습니다.

#!/usr/bin/env bash
find "$@" -name "file*"

find또 다른 접근 방식은 bash의 확장된 글로빙 기능과 글롭을 완전히 피하고 사용하는 것입니다 .

#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done

bash globstar옵션을 사용하면 재귀적으로 일치하는 데 사용할 수 있습니다 **.

globstar
      If set, the pattern ** used in a pathname expansion con‐
      text will match all files and zero or  more  directories
      and  subdirectories.  If the pattern is followed by a /,
      only directories and subdirectories match.

도트 파일(숨겨진 파일)을 찾아 포함하는 것처럼 100% 작동하게 하려면 다음을 사용하세요.

#!/usr/bin/env bash
shopt -s globstar
shopt -s dotglob
for file in te*/my\ files/**; do echo "$file"; done

echo루프 없이 직접 만들 수도 있습니다 .

echo te*/my\ files/**

답변2

배열은 어떻습니까?

$ tree Desktop/ Documents/
Desktop/
└── my folder
    └── more
        └── file
Documents/
└── my folder
    ├── folder
    └── more

5 directories, 1 file
$ SEARCH=(D*/my\ folder)
$ find "${SEARCH[@]}" 
Desktop/my folder
Desktop/my folder/more
Desktop/my folder/more/file
Documents/my folder
Documents/my folder/more
Documents/my folder/folder

(*)와일드카드와 일치하는 모든 배열로 확장됩니다. 그리고 각각 개별적으로 인용된 "${SEARCH[@]}"배열( )의 모든 요소로 확장됩니다 .[@]

뒤늦게야 발견 자체가 이런 일을 할 수 있다는 것을 깨달았습니다. 다음과 같은 것 :

find . -path 'D*/my folder/more/'

답변3

지금은 약간 구식이지만 이 질문에 대해 누구에게나 도움이 될 수 있다면 find 명령줄 인수 내에서 변수를 [[.space.]]인용하지 않고 RE의 조합 기호를 사용하는 $SEARCH것은 별표 대신 확장된 경로 이름에 특수 문자가 없는 한 작동하는 것입니다.

set -x
mkdir -p te{flon,nnis,rrine}/my\ files/more
SEARCH=te*/my[[.space.]]files/more
find $SEARCH

다음 결과를 제공합니다.

+ mkdir -p 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
+ SEARCH='te*/my[[.space.]]files/more'
+ find 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more'
teflon/my files/more
tennis/my files/more
terrine/my files/more

원하지 않는 문자를 글로빙하는 것을 방지하기 위해 별표( *)를 조합 요소(문자)로 바꿀 수 있습니다.

set -x
mkdir -p -- te{,-,_}{flon,nnis,rrine}/my\ files/more
SEARCH=te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more
find $SEARCH

다음과 같은 결과를 제공합니다.

+ mkdir -p -- 'teflon/my files/more' 'tennis/my files/more' 'terrine/my files/more' \
'te-flon/my files/more' 'te-nnis/my files/more' 'te-rrine/my files/more' \
'te_flon/my files/more' 'te_nnis/my files/more' 'te_rrine/my files/more'
+ SEARCH='te[[:alnum:][.space.][.hyphen.][.underscore.]]*/my[[.space.]]files/more'
+ find 'te-flon/my files/more' 'te_flon/my files/more' 'teflon/my files/more' \
'te-nnis/my files/more' 'te_nnis/my files/more' 'tennis/my files/more' \
'te-rrine/my files/more' 'te_rrine/my files/more' 'terrine/my files/more'
te-flon/my files/more
te_flon/my files/more
teflon/my files/more
te-nnis/my files/more
te_nnis/my files/more
tennis/my files/more
te-rrine/my files/more
te_rrine/my files/more
terrine/my files/more

줄을 줄이려면 을 또는 [.hyphen.]로 바꿀 수 있고 또는 로 바꿀 수 있습니다 .[.-.]-[.underscore.][._.]_



\가독성을 위해 직접 추가한 백슬래시( )를 사용하여 줄을 자릅니다 .

답변4

드디어 답을 알아냈습니다.

모든 공백에 백슬래시를 추가합니다.

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /\\ }

이 시점 SEARCH에서 te*/my\ files/more.

그런 다음 eval.

eval find ${SEARCH} -print

그것은 간단합니다! 를 사용하면 변수의 eval해석이 무시됩니다 .${SEARCH}

관련 정보