while 루프 -done<done<file 대신 명령

while 루프 -done<done<file 대신 명령

하위 폴더의 모든 파일을 현재 폴더로 이동하기 위해 이 스크립트를 사용합니다.

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호출을 실행할 필요가 없다는 의미입니다. -tGNU 확장입니다. 다른 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의 답변은 훌륭합니다.

관련 정보