하위 폴더의 모든 파일을 현재 폴더로 이동하기 위해 이 스크립트를 사용합니다.
while read f
do
mv "$f" .
done < file_list
file_list
이것은 훌륭하게 작동하지만 생성 해야합니다
find . -name *.avi > file_list
내가 원하는 것은 명령을 while 루프에 직접 추가하는 것입니다.
while read f
do
mv "$f" .
done < find . -name *.avi
하지만 배쉬는 나에게 말한다 -bash: syntax error near unexpected token `.'
find 명령을 while 루프로 파이프하는 간단한 솔루션은 무엇입니까?
답변1
여기에는 루프가 필요하지 않으며 find
다음과 같이 수행할 수 있습니다.
find . -name '*.avi' -exec mv {} . \;
답변2
프로세스 대체를 사용할 수도 있습니다.
while IFS= read -r f
do
mv -- "$f" .
done < <(find . -name '*.avi' )
쉘에서는 bash
파이프라인 방식과 비교하여 장점이 있습니다.아니요서브쉘에서 루프를 실행하면 루프 내에서 수행한 변수 할당이 나중에 손실되지 않습니다. bash
(또는 ) 에서는 zsh
다음을 수행하는 것이 좋습니다.
while IFS= read <&3 -rd '' f
do
mv -- "$f" .
done 3< <(find . -name '*.avi' -print0)
임의의 파일 이름을 처리하려면 NUL 구분 기호를 사용하고, 사용자에게 프롬프트가 표시될 수 있으며 stdin에서 답변을 읽을 수 있으므로 0 대신 fd 3을 사용하십시오. mv
이는 0을 사용한 경우 출력이 됩니다.find
또는 find
명령 자체를 사용하십시오.
find . -name '*.avi' -exec mv -t . {} +
사용한다는 +
것은 많은 매개변수를 한 번에 전달하므로 각 파일 mv
에 대해 mv
호출을 실행할 필요가 없다는 의미입니다. -t
GNU 확장입니다. 다른 mv
구현의 경우 다음과 같이 변경할 수 있습니다.
find . -name '*.avi' -exec sh -c 'exec mv "$@" .' sh {} +
답변3
올바른 방법은 파이프입니다
find . -name '*.avi' |
while read f
do
mv "$f" .
done
첫 번째 명령 ""의 결과는 find . -name *.avi
두 번째 명령에 제공됩니다.
이것을 파이프라고 합니다(기호에서 유래 |
). 파이프를 다음과 같은 임시 파일로 생각할 수 있습니다.
find . -name '*.avi' > file1.tmp
while read f
do
mv "$f" .
done < file1.tmp
rm file1.tmp
지적한 대로 파일 이름에 공백이나 개행 문자가 있으면 오류가 발생할 수 있습니다.
유일한 목적이 파일을 이동하는 것이라면 @Terdon의 명령을 사용하십시오.
또한 인용해야 합니다. *.avi
그렇지 않으면 두 번째 실행에서 중단됩니다.
find: paths must precede expression: `foo.avi'
find: possible unquoted pattern after predicate `-name'?
답변4
기존 두 답변 사이의 중간 위치는 "인라인"을 찾아 사용하는 것입니다.~을 위한반지 모양.
for f in `find . -name '*.avi' `
do
mv "$f" .
done
백틱을 사용하면 find 명령이 제자리에서 실행된 다음 해당 출력이 대체됩니다.
결점파일 이름에 공백과 예상치 못한 이상한 문자가 있으면 문제가 발생할 수 있습니다. @Terdon의 답변은 훌륭합니다.