여러 개의 파일 이름을 나열하고 각 입력 이름에 대해 새 이름을 출력하는 find
유틸리티(라고 부르겠습니다 util
)를 통해 파이프한 다음 각 파일의 이름을 이전 이름에서 새 이름으로 바꾸고 싶습니다.
가장 기본적인 해결책은 다음과 같습니다.
find . -print0 | while IFS= read -d '' -r old_name; do
new_name="$(echo "$file" | util)"
mv "$old_name" "$new_name"
done
이 접근 방식의 문제점은 util
각 파일 이름을 개별적으로 실행하기에는 너무 느리다는 것입니다. 따라서 해결책은 util
한 번만 시작하고 이 단일 프로세스를 통해 모든 파일 이름을 전송하는 것입니다.
find . -print0 >old_names
util <old_names >new_names
exec {old_fd}<old_names
exec {new_fd}<new_names
while IFS= read -d '' -r old_name <&$old_fd &&
IFS= read -d '' -r new_name <&$new_fd; do
mv "$old_name" "$new_name"
done
이것은 util
한 번만 시작되지만 더 이상 파이프가 아닙니다. 모든 파일을 tmp 파일에 나열하고 util
이 tmp 파일을 실행하여 다른 tmp 파일을 가져온 다음 실제로 이름 바꾸기를 시작해야 합니다. .
파이프라인 방식으로 이 작업을 수행하기 위해 다음을 시도했습니다.
mkfifo old_names new_names
find . -print0 | tee old_names | util >new_names &
exec {old_fd}<old_names
exec {new_fd}<new_names
while IFS= read -d '' -r old_name <&$old_fd &&
IFS= read -d '' -r new_name <&$new_fd; do
mv "$old_name" "$new_name"
done
util
불행히도 이것은 입력/출력이 버퍼링되는 방식 에 따라 교착 상태가 될 수 있습니다 .
그래서 제 질문은: bash에서 이 작업을 수행하는 올바른 방법은 무엇입니까?
답변1
파이프를 연결하지 않는 솔루션:
find . -print > infiles
cat infiles | util > outfiles
parallel mv ::::+ infiles outfiles
장점: 매우 간단합니다. 단점: 이름 바꾸기는 util
완료 후에만 시작됩니다. 임시 파일 2개.
find . -print > infiles
cat infiles | util | parallel -j1 mv ::::+ infiles -
장점: 이름 지정이 util
시작되면 이름 바꾸기도 시작됩니다. 단점: 임시 파일이 1개입니다.
find . -print | util | parallel -j1 mv ::::+ <(find . -print) -
장점: 이름 지정이 util
시작되면 이름 바꾸기도 시작됩니다. 단점: 현재 디렉터리를 변경할 필요가 없습니다. 그렇지 않으면 두 find
s가 동일한 결과를 제공하지 않을 수 있습니다.
답변2
변환(util)의 복잡성에 따라 이름 바꾸기(Larry Wall의 이름 바꾸기)를 사용할 수 있습니다.
또는
util
출력 이름 쌍을 정렬합니다 : old-name
new-name
, 그런 다음
find . -print0 | util | xargs -n2 mv -T
또는
이런 것을 시도해 보세요.
function a() {
echo -n "$1 "
echo "$1" | sed -e s/a/b/g
}
… | while read arg; do
a "$arg"
done