find
여러 하드 드라이브에 있는 파일에 액세스하는 명령의 속도를 높이기 위해 병렬화를 활용하려고 합니다. 불행하게도 병렬화가 무시되거나 변수가 채워지지 않습니다.
found=""; IFS=$'\n'
for hdd in "${hdd_list[@]}"
do
found+=$'\n'$(find "$hdd" -name "*filter*" -type f &) # ignores parellelization
found+=$'\n'$(find "$hdd" -name "*filter*" -type f) & # doesn't fill variable
done
임시 파일을 사용하지 않고도 이것이 가능합니까?
답변1
명령 대체는 계속하기 전에 명령 내부로 열린 파이프에서 모든 데이터를 가져올 때까지 기다립니다. 스크립트를 계속 실행하는 동안 쉘이 백그라운드에서 계속 데이터를 읽도록 하는 것은 필요 이상으로 복잡합니다. (그런데 이는 명령 대체의 명령이 상위 항목을 먼저 분기하고 종료하는 등 이상한 작업을 수행하더라도 파이프가 마지막으로 닫힐 때(그렇다면) 여전히 모든 출력을 얻을 수 있음을 의미합니다.) 따라서 프로세스를 배치합니다. 백그라운드 명령 대체에서( $(... &)
유용하지 않습니다.
전체 할당을 백그라운드( foo=... &
)에 넣는 것도 작동하지 않습니다. 백그라운드 작업은 별도의 프로세스에서 실행되어야 하고 해당 백그라운드 프로세스는 기본 셸 프로세스 메모리의 셸 변수를 변경할 수 없기 때문입니다.
모든 프로세스를 개별적으로 파이프에 연결하고 find
병렬로 실행 및 인쇄하도록 구성할 수 있지만 파이프 버퍼가 너무 커서 동시에 모든 프로세스에서 읽어야 함을 의미합니다. 쉘에서는 이 작업을 수행하기가 어렵습니다 select()
. (글쎄, 일부 쉘에는 있을 수도 있습니다.)
하지만 임시 파일을 사용하는 간단한 솔루션이 있기 때문에 모든 것이 너무 복잡합니다.
find
전체 줄(항목)만 쓰고 순서에 신경 쓰지 않는다는 점에서 구현이 훌륭 하다면 모든 출력을 단일 파일로 리디렉션할 수 있습니다.
f=$(mktemp)
for hdd in "${hdd_list[@]}"; do
find "$hdd" ... &
done >> "$f"
# read "$f"
rm -f "$f"
그러나 그렇지 않은 경우나 확실하게 확인하고 싶다면 임시 디렉터리와 각 디렉터리에 대한 출력 파일을 만드세요 find
.
d=$(mktemp -d)
i=1
for hdd in "${hdd_list[@]}"; do
find "$hdd" > "$d/out$i.tmp" &
i=$((i+1))
done
cat "$d"/*.tmp > "$d/all.out"
# read "$d/all.out"
rm -rf "$d"
물론 첫 번째 파일에서는 임시 파일을 건너뛰고 루프에서 직접 읽을 수 있습니다.
find
배열과 함께 쉘을 사용하고 있으므로 출력 도 배열에 저장하고 싶을 수도 있습니다 . 예를 들어 readarray
Bash에서는 각 행을 다른 배열 요소에 배치합니다.
readarray -t files < <(find ...)
답변2
parset
이를 위해 제작됨:
parset hd find {} -name \""*filter*"\" -type f ::: "${hdd_list[@]}"
그러나 임시 파일을 사용합니다. 그들은 당신을 위해 청소되므로 당신이 그들을 처리할 필요가 없습니다.
답변3
"&" 사용의 전체 의미를 이해하지 못하는 것 같습니다.
짐승의 본성백그라운드 프로세스의 경우할 수 없다상위 프로세스에서 백그라운드 하위 프로세스 콘텐츠에 액세스...(변수가 전역 변수로 선언되었는지 여부에 관계없이).
겪고 있는 문제는 다른 질문에 설명된 것과 동일합니다.우편. 기본적으로 임시 파일은 문제를 피할 수 있는 유일한 방법입니다.
답변4
특히 병렬화의 경우 find
다음을 확인하세요.fdfind
find
이는 기본적으로 멀티스레딩의 향상된 버전입니다.
그래도 문제가 해결되지 않으면 다음 을 fdfind
사용해 보십시오. xargs
그러면 명령이 병렬로 실행됩니다. 다음에서 빌림이 문제, 다음과 같이 시도해 볼 수 있습니다(비록 100% 확신할 수는 없으므로 작동하기 전에 수정해야 할 수도 있음).
found="$( printf "%s\0" "${hdd_list[@]}" | xargs -0 -I {} find {} -name "*filter*" -type f )"
작동 방식:
printf "%s\0" "${hdd_list[@]}"
: 널 문자를 구분자로 사용하여 목록을 인쇄합니다.
| xargs -0 -I {} ...
: null로 구분된 입력( -0
)을 사용하여 stdin을 가져와 다음 명령을 호출합니다. 모든 인스턴스를 찾아 {}
입력 필드로 바꿉니다.