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


9

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합니다.

내가하려는 일을 어떻게 달성 할 수 있습니까? 구글은 나를 도와주지 않았다 :(


@KasiyA bash를 사용하고 있습니다. 내가 전에 그 구성을 보지 못 했으므로 다른 것을 사용해야합니다. 명령 SEARCH: command not found은 명령 find -print이 실행되는 결과를 낳습니다 .
Paddy Landau

어둠 속에서 촬영했지만 인용은 어떻습니까? find "${SEARCH}" -print?
Alaa Ali

@AlaaAli 아니요, 인용하면 Bash가 와일드 카드를 사용하지 못하므로 작동하지 않습니다. (예제에서) 이름이있는 경로를 찾습니다 te*/'my files'/more.
Paddy Landau

답변:


9

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

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

변수로 사용해야 하는 경우 조금 더 복잡해집니다.

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

경고:

eval이와 같이 사용 하는 것은 안전하지 않으며 파일 이름에 특정 문자가 포함될 수있는 경우 임의적이고 유해한 코드가 실행될 수 있습니다. 자세한 내용은 bash 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

globstarbash는 옵션을 사용할 수 있습니다 **재귀 적으로 일치 :

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
나는 terdon이 작성한 유용한 의견 (다른 사람들의 유용한 의견을 잊지 않음) 때문에이 답변으로 설정했습니다. 명령 줄에서 Bash의 globbing 기능을 사용하여 스크립트를 정렬하려고하는 대신 여러 경로를 스크립트에 전달했습니다. 잘 작동한다.
Paddy Landau

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/'

영리한 생각이지만 아쉽지만 작동하지 않습니다. 왜? 경로 자체는 변수로 유지되기 때문에; 따라서, INPUTPATH='te*/my files/moreSEARCH=(${INPUTPATH}). 내가하는 방법이 어떻게 달라 지더라도 여전히 작동하지 않는 결과가 나타납니다. 불가능 해 보인다!
Paddy Landau

물론 이것은 사실이지만 OP는 스크립트로해야합니다. 와일드 카드 확장이 훨씬 더 복잡해지고 작동하지 않기 때문에 상황이 바뀝니다.
terdon

@PaddyLandau 어떤 경우에 find-path필터를 사용할 수 없습니까? 와일드 카드를 사용하므로 확장이 필요하지 않습니다.
muru

@muru 흥미 롭습니다. 에 대해 몰랐습니다 -path. 지난 10 분 동안 나는 답을 알아 냈다 : use eval! 보다 간단한 것 같습니다 -path.
Paddy Landau

2
@ terdon과 muru 그리고 모두 : 감사합니다. 나는 당신이 모두 말한 것을 들었고, 나는 스크립트가 한 가지 일을하고 Bash globbing이 여러 파일이나 경로를 스크립트에 전달하게해야한다는 것을 깨달았습니다. 따라서 스크립트를 수정했습니다. Linux 철학과 잘 작동하고 더 잘 맞습니다. 다시 감사합니다!
Paddy Landau

0

마침내 답을 찾았습니다.

모든 공백에 백 슬래시를 추가하십시오.

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

이 시점에서 SEARCH포함 te*/my\ files/more합니다.

그런 다음을 사용하십시오 eval.

eval find ${SEARCH} -print

그렇게 간단합니다! 사용 eval${SEARCH}변수 의 해석을 무시합니다 .



@terdon 경고 해 주셔서 감사합니다. 드로잉 보드로 돌아갑니다!
Paddy Landau

예, 이것은 놀랍습니다. 방금 다른 접근법으로 답변을 업데이트했습니다. 대신 globbing을 사용하지 않는 이유는 무엇입니까? 그래도 문제가 해결되지 않으면 최종 목표가 무엇인지, 패턴을 변수로 사용해야하는 이유를 설명하는 Unix & Linux 에 새로운 질문을 게시하는 것이 좋습니다 . 이 유형의 것은 더 나은 답변을 얻는 것이 좋습니다.
terdon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.