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


98

내가 알고 싶은 정확히 무엇을 {} \;하고 {} \+| 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'

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


진짜 질문은 간단합니다. 왜 첫 번째는 작동하고 두 번째는 작동하지 않습니까? (1) 찾기. -type f -iname ' .cpp'-exec mv {} ./test/ \; (2). -type f -iname ' .cpp'
Hossain

답변:


185

매뉴얼 페이지 (또는 온라인 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가 명령 줄을 빌드하는 것과 거의 같은 방식으로 빌드됩니다. 명령 내에서`{} '의 인스턴스는 하나만 허용됩니다. 명령은 시작 디렉토리에서 실행됩니다.


1
실제로 어떻게 작동하는지 알고 있습니다.이 설명서를 여러 번 살펴 보았지만 {} \에서는 작동하지만 {} +를 사용하면 오류 메시지가 표시됩니다. Windows에서 Cygwin을 사용하고 있습니다.
Shahadat Hossain 2011

1
@Shahadat : ​​"매뉴얼 페이지에서"전에 부분을 읽었습니까? 당신은 넣어 한 ./test/사이 {}+, 그러나 공백이 아닌 문자는이 사이에 허용되지 않습니다.
Lekensteyn 2011

ru는 {}와 + 사이에 ./test/를 넣어서는 안된다고 말합니다. 그러면 mv 명령이 작동하는 방법; mv는 소스가 {}이고 대상이 ./test/이고 +로 종료되어야합니다. 당신이 옳다고 생각하는 명령을 써주시겠습니까?
Shahadat Hossain 2011

@Shahadat : ​​나는 당신이 달성하려는 것을 봅니다. Windows는 프로그램 실행 속도가 느리므로이를 하나의 명령으로 결합하려고합니다. 대답에 대안을 추가하겠습니다.
Lekensteyn 2011

1
+명령은 파일을 "끝"(대신이 아닌)에 고정하기 때문에 약간 이상한 AFAIU이므로 전혀 {}사용하는 이유는 무엇입니까 {}? 이것은 혼란 스럽습니다. -t내가 모르는 옵션에 감사드립니다. 옵션이 -exec +문제 의 해결 방법으로 만들어진 것 같습니다 !
e2-e4 2017

6

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

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

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

Ubuntu 14.04 ( BASHZSH 셸 사용)에서 테스트 했으며 동일하게 작동합니다.

그러나 +표지판을 사용할 때 실제로 exec명령 의 끝에 있어야하는 것 같습니다 .


{}요구는 인용 수 fishrc조개가 아니라에서 zsh, bash도 보른 또는 CSH 가족의 다른 포탄입니다.
Stephane Chazelas

@StephaneChazelas Yep, 우분투에서 bash. 흥미롭게도 MacOS에서 인용하지 않으면 문제가 발생했습니다 (사용 zsh). 하지만 다시 시도 할 수있는 Mac이 없습니다 ...
arvymetal

3

지원하지 않는 구현 이나 지원하지 않는 구현 에 find -iname ... -exec mv -t dest {} +대한 표준 동등한 것은 셸을 사용하여 인수를 다시 정렬하는 것입니다.find-inamemv-t

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

를 사용 -name '*.[cC][pP][pP]'하면 c또는 의 대문자 버전을 결정하기 위해 현재 로케일에 의존하지 않아도됩니다 p.

참고 +반면에, ;(포탄 물론 제외하지 않습니다 피해를 인용하지만 원하는 쉘이 그렇게 인용 할 필요가 없습니다 특별하지 않다 rc가 지원하지 않는 \인용 문 연산자로).

후행 /인은 /dest/dir/그 때문에입니다 mv대신 이름을 변경의 오류와 함께 실패 foo.cpp/dest/dir단 한 곳 경우 cpp파일이 발견되었고 /dest/dir존재하지 않았거나 디렉토리 (또는 디렉토리에 대한 심볼릭 링크)가 아니었다.


+1 ... 명령 실행에 대한 예비로서의 쉘 내 작업은 실제로 다양한 사용 사례에 유용합니다.
Cbhihe 2017

0
find . -name "*.mp3" -exec mv --target-directory=/home/d0k/Музика/ {} \+

다른 사람들이 배울 수 있도록 답변에 설명을 추가하십시오
Nico Haase

설명을 요구하는 질문에 답해야합니다. 코드 전용은 답이 아닙니다.
Lajos Arpad

-1

없음의 차이 +와는 \;역전한다. +exec 명령 끝에 파일을 추가 한 다음 exec 명령을 실행하고 \;각 파일에 대해 명령을 실행합니다.

문제는 탈출하거나 종료 할 필요 find . -type f -iname '*.cpp' -exec mv {} ./test/ \+find . -type f -iname '*.cpp' -exec mv {} ./test/ +없다는 것입니다.+

xargs 나는 오랫동안 사용하지 않았지만 +처럼 작동한다고 생각합니다.


나는 또한 이것을 시도했지만 동일한 오류 메시지가 나타납니다. 더욱이, 나는 +만을 사용하는 것을 발견 한 모든 곳에서 내 cygwin에서 나는 작동하기 위해 \ + 또는 "+"를 사용해야합니다.
Shahadat Hossain 2011

오 이것은 cygwin 환경입니다. 죄송합니다. 모르겠습니다. cygwin 셸을 사용하지 않고 * nix를 사용합니다.
Mike Ramirez 2011

1
의 Hossain @Shahadat 시도 -name "*.cpp"좀 어려운 정규식 검색을 수행하려는 경우가 아니면 내가 거의 -iname처럼 -iname를 사용하지 않는 '일 ??? * \ cpp에.. "
마이크 라미레즈

1
@ 마이크 : 나는 당신이 오해의 차이라고 생각 -iname하고 -name. -iname대소 문자를 구분하지 않는 버전이며 -name정규식 처리에 차이가 없습니다. 게시하기 전에 명령을 시도하는 것이 좋습니다. 명령이 내 셸에서도 실패합니다.
Lekensteyn 2011

1
@Lekensteyn 귀하의 의견 이전에 이미 입증되었습니다. 나는 당신의 포스트 이전에 Shahadat을 인정했다고 생각했습니다. 그것은 단순한 "OK"였습니다. 아니요, 수동으로 실행하지 않았으며 머리 위에서 실행했으며 find와 함께 해당 형식의 정규식 검색을 거의 사용하지 않습니다. 그것은 단지 '도움이 될 수있는'유형의 일이었습니다.
Mike Ramirez 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.