간단히 말해서:
Q: 카운터 find -exec
루핑을 유지하려면 어떻게 해야 합니까?
내 사용 사례:
여기저기 흩어져 있는 디렉토리를 많이 옮겨야 해서 이렇게 했습니다.
find . -type d -name "prefix_*" \
-exec sh -c '
new_path="/new/path/$(basedir "$1")";
[ -d "$new_path" ] || mv "$1" "$new_path";
' find_sh {} \;
(실제 명령은 그것을 구성하는 요소에 대한 일부 메타데이터를 읽었기 때문에 더 복잡합니다 /new/path
. 어쨌든 명령 자체에 대해 논쟁하고 싶지는 않습니다. 이는 질문의 일부가 아니라 사용 사례일 뿐입니다.)
잘 작동하지만 시간이 꽤 오래 걸리므로 진행 상황을 추적하고 싶습니다.
그래서 파일에 쓸 카운터를 추가했습니다.
i=$(cat ~/find_increment || echo 0);
echo $((i+1)) | tee ~/find_increment;
이것도 훌륭하게 작동하지만 다음과 같은 느낌이 듭니다.진짜약 100,000개의 디스크 읽기 및 쓰기 작업을 수행하는 것은 좋지 않은 생각입니다.
디스크 대신 쓰기를 고려했지만 ramdisk
이 작업을 수행하는 데 필요한 환경에는 해당 옵션이 없습니다.
실행 사이에 카운터를 유지하는 더 좋은 방법이 있습니까 -exec
?
답변1
find
find
순수한 명령을 사용하는 대신 루프나 GNU 와 while read
결합 할 수 있습니다 parallel
. 발견 된 모든 경로에 대해 새 쉘을 시작할 필요가 없기 때문에 둘 다 아마도 둘 중 하나보다 더 빠를 것입니다 find
.-exec
find
GNU Parallel을 사용한 솔루션
GNU와 비교하면 다음과 parallel
같은 장점이 있습니다 while read
.
- 올바른 결과를 얻는 것이 더 쉽습니다. 아니요
IFS=
, 또한-r
필수입니다. - 내장된 작업 번호 변수
{#}
.
보다 편리한 문자열 교체를 확인하려면 다음을 확인하세요.지도 시간. - 필요한 경우 쉽게 병렬화할 수 있습니다.
제거되면-j1
기본적으로 코어 수만큼 작업자 스레드를 갖게 됩니다.
script='
echo Processing job number {#}
new_path="/new/path/$(basedir {})"
[ -d "$new_path" ] || mv {} "$new_path"
'
find … -print0 | parallel -0 -j1 "$script"
는 에서 읽은 올바르게 참조된 항목 {}
으로 대체 됩니다 . 다시 인용 하지 마십시오 .parallel
stdin
{}
parallel
스크립트를 시작한 것과 동일한 셸을 사용하여 스크립트를 실행합니다. 스크립트 에서 함수를 parallel
사용하기 시작하면 .bash
bash
"읽으면서 읽기"를 사용하는 솔루션
find … -print0 |
while IFS= read -r -d '' old_path; do
echo Processing job number "$((++job))"
new_path="/new/path/$(basedir "$old_path")"
[ -d "$new_path" ] || mv "$old_path" "$new_path"
done
답변2
가능하다면 거기에 카운터를 저장하여 /dev/shm/
디스크 쓰기를 방지하세요.
=> /dev/shm/find_increment
대신 사용하세요 ~/find_increment
.