생성된 "시작점" 세트에서 find를 호출해야 하지만 일부 경로가 유효하지 않을 수 있습니다.
paths() {
#
# mock version of the generator
#
echo /bin
echo kjsdfhk
echo /etc
}
find $(paths) -type f name foo.sh
내 문제는 경로가 유효한지 알 수 없고, 그렇지 않은 경우 조용히 무시하고 싶다는 것입니다. 나에게 가장 쉬운 일은 지금이다.
paths \
| while read path;
do
test -e "$path" || continue
find "$path" -type f -name foo.sh
done
하지만 이것은 비용이 많이 듭니다.찾다모든 유효한 경로에 대해 그리고 전체 코드가 루프 내에서 호출될 수 있으므로 보다 효율적인 방법을 찾고 싶습니다.
간단하고 매우 유닉스적인 솔루션은 다음과 같습니다.찾다STDIN에서 "시작점"을 읽으십시오.
paths \
| while read path;
do
test -e "$path" || continue
done \
| find - -type f -name foo.sh
그것 빼고는...찾다이는 지원되지 않습니다! :)
어떤 아이디어가 있나요?
경로는 사용자가 제공하므로 공백(및 기타 흥미로운 사항)을 고려해야 합니다. 또한 POSIX를 목표로 삼고 있지만 /bin/sh
희생될 수도 있습니다. (아, STDERR 전체를 침몰시키는 것도 /dev/null
선택 사항이 아닙니다...)
고쳐 쓰다:죄송합니다. bash만 사용할 수 있다는 점을 언급하는 것을 잊어버렸습니다. POSIX 주석 때문에 더 혼란스러울 수 있습니다. 실제로 코드는 Bash 스크립트에서 소스 코드 조각을 찾고 있으며, 그 중 대부분은 현재 다음 위치에 있습니다.쉿향후 버전에서는 일부 굴욕감을 없앨 수도 있습니다. 따라서 더 많은 bashism을 추가하는 것을 피할 수 있다면 멋질 것입니다. 그러나 @stephane의 답변 (지금 투표하십시오!)처럼 아무리 우아하더라도 "zshisms"를 감당할 여유가 없습니다.
답변1
zsh
배열에 다음과 같은 경로가 있는 경우 :
files=($(paths))
paths
(이렇게 하면 출력이 공백, 탭 개행 또는 널로 분할됩니다) 또는:
files=(${(f)"$(paths)"})
줄을 나누려면 다음과 같이 하세요.
find $^files(N) -type f -name foo.sh
또는 디렉토리로 제한하려는 경우:
find $^files(/N) -type f -name foo.sh
이제 이러한 파일이 없으면 다음이 실행될 수 있습니다.
find -type f -name foo.sh
일부 find
구현(예: GNU)의 경우 이는 현재 디렉토리에서 검색하는 것을 의미합니다. 이를 방지하려면 다음을 수행할 수 있습니다.
dirs=($^files(/N))
(($#dirs)) && find $dirs -type f -name foo.sh
또는:
setopt cshnullglob
find $^files(/) -type f -name foo.sh
이제 zsh
더 이상 필요하지 않습니다 find
. 간단하게 다음을 수행할 수 있습니다.
files=($^files/**/foo.sh(.N))
!
이렇게 하면 파일이 유사하거나 -name
차단되어 있는 경우에도 작업이 용이해집니다.find
그러나 파일이 디렉토리에 대한 심볼릭 링크인 경우( find
여기서 파일을 찾지는 않지만 실제로 원하는 것일 수 있음) zsh
상황은 다릅니다 .
답변2
bash를 사용하고 있으므로 경로 목록을 다음 위치에 저장하십시오.대량으로. 배열을 반복하여 기존 경로의 배열을 만듭니다. 결과 배열이 비어 있으면 특별한 경우가 필요합니다. 그렇지 않으면 find
오류가 발생하거나 현재 디렉터리를 탐색하게 됩니다.
완전히 견고하려면 경로 매개변수가 a로 시작하지 않도록 해야 합니다 -
. 그렇지 않으면 find
옵션이나 기본 매개변수로 해석됩니다.
paths=(/some/where around/here -print 'one with
odd spaces')
existing_paths=()
for x in "${paths[@]}"; do
if [ -e "$x" ]; then
if [[ "$x" = -* ]]; then x="./$x";; fi
existing_paths+=("$x")
fi
done
if [[ ${#existing_paths[@]} -ne 0 ]]; then
find "${existing_paths[@]}" -type f -name foo.sh
fi
답변3
Python을 사용하여 경로가 존재하는지 테스트하고 찾은 NUL로 구분된 경로를 에코하고 이를 입력하여 xargs
에 전달할 수 있습니다. 단, Python 출력 길이가 find를 한 번만 호출해야 하는 최대 인수 길이를 초과하지 않는 한은 다음과 같습니다 find
.
python -c 'import os, sys; sys.stdout.write("\0".join([x for x in sys.argv[1:] if os.path.exists(x)]) + "\0")' a\ b xyz abc| xargs -0 --no-run-if-empty find
Python 부분(-c에 대한 작은따옴표 인수):
- 필요한 모듈을 가져와
os
명령sys
에 사용 - 매개변수를 반복
a b
하고xyz
사용abc
for x in sys.argv[1:]
- 경로가 존재하는 경우에만 목록에 넣으십시오.
[x ... if os.path.exists(x)]
- NUL을 사용하여 목록에 가입하고 NUL을 추가한 후 stdout에 기록합니다.
sys.stdout.write("\0".join[...] + "\0")
빈 디렉토리가 있는 경우 touch a\ b xyz
처음 두 개의 인수가 발견되었지만 abc
찾을 수 없으며 find가 후자 경로로 전달되지 않는 것을 볼 수 있습니다.
답변4
이것이 당신에게 효과가 있다면
$(paths) 찾기 -f 이름 foo.sh를 입력하세요.
그런 다음 유효한 경로만 에코하도록 경로 기능을 변경할 수 있습니다.
if [ -d "$path" ]; then echo $path fi
또는 경로가 파일일 수도 있는 경우
if [ -d "$path" ] || [ -e "$path" ]; then echo $path fi
이 방법으로 find는 한 번만 실행됩니다. 경로 함수를 수정할 수 없는 경우 find 명령에 전달하기 전에 모든 유효한 경로를 필터링하는 다른 함수를 항상 생성하여 잘못된 경로가 전달되지 않도록 할 수 있습니다.