code

find -exec mv {} ./target/ + 작동하지 않는 이유는 무엇입니까?

codestyles 2020. 8. 25. 08:03
반응형

find -exec mv {} ./target/ + 작동하지 않는 이유는 무엇입니까?


내가 정확히 무엇을 알고 싶어 {} \;하고 {} \+| xargs ...않습니다. 설명과 함께이를 명확히하십시오.

아래 3 개의 명령은 동일한 결과를 실행하고 출력하지만 첫 번째 명령은 약간의 시간이 걸리며 형식도 약간 다릅니다.

find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file

첫 번째는 file명령에서 오는 모든 파일에 대해 명령을 실행하기 때문 find입니다. 따라서 기본적으로 다음과 같이 실행됩니다.

file file1.txt
file file2.txt

그러나 후자의 2 -exec명령은 아래와 같은 모든 파일에 대해 파일 명령을 한 번 실행합니다.

file file1.txt file2.txt

그런 다음 첫 번째 명령은 문제없이 실행되지만 두 번째 명령은 오류 메시지를 표시하는 다음 명령을 실행합니다.

find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'

를 사용하는 명령의 {} \+경우 오류 메시지가 표시됩니다.

find: missing argument to `-exec'

왜 그런 겁니까? 누구든지 내가 뭘 잘못하고 있는지 설명해 주시겠습니까?


매뉴얼 페이지 (또는 온라인 GNU 매뉴얼 ) 거의 모든 것을 설명합니다.

find -exec 명령 {} \;

각 결과에 대해 command {}실행됩니다. 의 모든 항목은 {}파일 이름으로 대체됩니다. ;쉘이 해석하지 못하도록 슬래시가 접두어로 붙습니다.

find -exec 명령 {} +

각 결과는 추가 command되고 나중에 실행됩니다. 명령 길이 제한을 고려하면이 명령이 나를 지원하는 매뉴얼 페이지와 함께 더 많이 실행될 수 있다고 생각합니다.

명령의 총 호출 수는 일치하는 파일 수보다 훨씬 적습니다.

매뉴얼 페이지에서 다음 인용문을 참고하십시오.

명령 줄은 xargs가 명령 줄을 빌드하는 것과 거의 같은 방식으로 빌드됩니다.

어떤 문자 사이에 허용되지 않습니다 이유 {}+공백을 제외하고. +find는 인수가 명령에 추가되어야 함을 감지합니다 xargs.

해결책

운 좋게도의 GNU 구현은 또는 더 긴 매개 변수 mv를 사용하여 대상 디렉토리를 인수로 받아 들일 수 있습니다 . 사용법은 다음과 같습니다.-t--target

mv -t target file1 file2 ...

귀하의 find명령이된다 :

find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+

매뉴얼 페이지에서 :

-exec 명령;

명령을 실행하십시오. 0 상태가 반환되면 참. 찾을 다음 모든 인수는`; '로 구성된 인수가 될 때까지 명령에 대한 인수로 간주됩니다. 만난다. 문자열`{} '는 find의 일부 버전에서와 같이 단독 인 인수뿐만 아니라 명령에 대한 인수에서 발생하는 모든 곳에서 처리되는 현재 파일 이름으로 대체됩니다. 이 두 구조는 쉘에 의한 확장으로부터 보호하기 위해 이스케이프 (`\ '로)하거나 인용해야 할 수 있습니다. -exec 옵션 사용의 예는 EXAMPLES 섹션을 참조하십시오. 지정된 명령은 일치하는 각 파일에 대해 한 번씩 실행됩니다. 명령은 시작 디렉토리에서 실행됩니다. -exec 조치 사용과 관련하여 피할 수없는 보안 문제가 있습니다. 대신 -execdir 옵션을 사용해야합니다.

-exec 명령 {} +

-exec 조치의이 변형은 선택한 파일에서 지정된 명령을 실행하지만 명령 줄은 선택한 각 파일 이름을 끝에 추가하여 작성됩니다. 명령의 총 호출 수는 일치하는 파일 수보다 훨씬 적습니다. 명령 줄은 xargs가 명령 줄을 빌드하는 것과 거의 같은 방식으로 빌드됩니다. 명령 내에서`{} '의 인스턴스는 하나만 허용됩니다. 명령은 시작 디렉토리에서 실행됩니다.


ZSH 셸을 사용하여 Mac OSX 에서 동일한 문제가 발생했습니다 .이 경우에 대한 옵션 이 없으므로 다른 솔루션을 찾아야했습니다. 그러나 다음 명령이 성공했습니다.-tmv

find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;

비밀은 중괄호를 인용하는 것이 었 습니다 . exec명령 끝에 중괄호를 사용할 필요가 없습니다 .

I tested under Ubuntu 14.04 (with BASH and ZSH shells), it works the same.

However, when using the + sign, it seems indeed that it has to be at the end of the exec command.


The standard equivalent of find -iname ... -exec mv -t dest {} + for find implementations that don't support -iname or mv implementations that don't support -t is to use a shell to re-order the arguments:

find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
  exec mv "$@" /dest/dir/' sh {} +

By using -name '*.[cC][pP][pP]', we also avoid the reliance on the current locale to decide what's the uppercase version of c or p.

Note that +, contrary to ; is not special in any shell so doesn't need to be quoted (though quoting won't harm, except of course with shells like rc that don't support \ as a quoting operator).

The trailing / in /dest/dir/ is so that mv fails with an error instead of renaming foo.cpp to /dest/dir in the case where only one cpp file was found and /dest/dir didn't exist or wasn't a directory (or symlink to directory).


no, the difference between + and \; should be reversed. + appends the files to the end of the exec command then runs the exec command and \; runs the command for each file.

The problem is find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ should be find . -type f -iname '*.cpp' -exec mv {} ./test/ + no need to escape it or terminate the +

xargs I haven't used in a long time but I think works like +.

참고URL : https://stackoverflow.com/questions/5607542/why-does-find-exec-mv-target-not-work

반응형