저는 계속해서

find . -name "FILENAME" -exec rm {} \; 

주로 -exec 부분이 정확히 어떻게 작동하는지 알 수 없기 때문입니다. 중괄호, 백 슬래시 및 세미콜론의 의미는 무엇입니까? 다른 사용 사례가 있습니까? 그 구문?

댓글

  • @Philippos : 요점을 알겠습니다. 매뉴얼 페이지는 참고 자료라는 것을 명심하십시오. 구문을 찾는 문제에 대한 이해가 있어야합니다. 주제를 처음 접하는 사람에게는 유용하기 위해 종종 암호화되고 형식적입니다. 허용되는 답변은 man 페이지 항목의 약 10 배 길이라는 것을 알 수 있습니다. ‘ 이유가 있습니다.
  • 이전 POSIX man 페이지에서도 유틸리티 _ 이름 또는 인수를 읽습니다. 두 문자 만 포함하는 ” {} “는 대체됩니다. d는 현재 경로 이름 으로 충분합니다. 추가로 귀하의 질문과 마찬가지로 -exec rm {} \;에 대한 예가 있습니다. 제 시대에는 ” 큰 회색 벽 “, 인쇄 된 페이지 (종이는 저장 공간보다 저렴했습니다). 그래서 나는 이것이 주제를 처음 접하는 사람에게 충분하다는 것을 알고 있습니다. 마지막 질문은 여기서 물어볼 수 있습니다. 안타깝게도 @Kusalananda도 나 자신도 이에 대한 답을 갖고 있지 않습니다.
  • @Philippos 🙂 오, 는 ” ” 차트의 규모를 벗어났습니다.
  • Comeon @Philippos. Kusalananda에게 그가 맨 페이지를 개선하지 않았다고 정말로 말하고 있습니까? 🙂
  • @ZsoltSzilagy 나는 그렇게 말하거나 의미하지 않았습니다. 그는 당신을 아주 잘 먹였습니다. 나는 당신이 혼자서 먹을 수있을만큼 충분히 늙었다 고 생각합니다. (-;

답변

이 답변은 다음 부분으로 구성됩니다.

  • -exec
  • 의 기본 사용법

  • sh -c와 함께 -exec 사용 div>
  • -exec ... {} + 사용
  • -execdir 사용

-exec

의 기본 사용법

-exec 옵션은 다음과 같은 선택적 인수가있는 외부 유틸리티를 사용합니다. 인수 및 실행합니다.

{} 문자열이 주어진 명령의 아무 곳에 나 있으면 각 인스턴스는 현재 처리중인 경로 이름으로 대체됩니다 ( 예 : ./some/path/FILENAME). 대부분의 쉘에서 두 문자 {}는 따옴표로 묶을 필요가 없습니다.

명령어 find가 끝나는 위치를 알기 위해 ;로 종료되어야합니다 (나중에 추가 옵션이있을 수 있음). 에스). 셸에서 ;를 보호하려면 \; 또는 ";"로 인용해야합니다. , 그렇지 않으면 쉘에서 find 명령의 끝으로 인식합니다.

예 (\ 처음 두 줄의 끝은 줄 연속만을위한 것입니다) :

find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} ";" 

모든 일반 파일을 찾습니다 (-type f)의 이름이 현재 디렉토리 안 또는 아래의 패턴 *.txt와 일치합니다. 그런 다음 grep -q를 사용하여 찾은 파일에서 hello 문자열이 발생하는지 테스트합니다 (출력을 생성하지 않고 종료 만 상태). 문자열이 포함 된 파일의 경우 cat가 실행되어 파일의 내용을 터미널에 출력합니다.

-exec-type 및 iv id = “3d1084b1c1과 마찬가지로 find에서 찾은 경로 이름에 대한”테스트 “역할도합니다. “>

그렇습니다. 명령이 0 종료 상태 ( “성공”을 의미)를 반환하면find명령의 다음 부분이 고려되고 그렇지 않으면find명령은 다음 경로 이름으로 계속됩니다. 이것은 위의 예에서hello문자열을 포함하는 파일을 찾는 데 사용되지만 다른 모든 파일은 무시합니다.

위의 예는 가장 일반적인 두 가지 사용을 보여줍니다. -exec의 경우 :

  1. 검색을 추가로 제한하기위한 테스트
  2. 발견 된 항목에 대한 작업 수행 경로 이름 (일반적으로 반드시 그런 것은 아니지만 find 명령 끝)

sh -c

-exec가 실행할 수있는 명령은 외부 유틸리티로 제한됩니다. 선택적 인수와 함께.-exec와 함께 쉘 내장, 함수, 조건부, 파이프 라인, 리디렉션 등을 직접 사용하는 것은 sh -c 하위 셸.

bash 기능이 필요한 경우 iv id = 대신 bash -c를 사용합니다. “73af3270ae”> .

sh -c는 명령 줄에 제공된 스크립트로 /bin/sh를 실행합니다. 그 뒤에 해당 스크립트에 대한 선택적 명령 줄 인수가옵니다.

find없이 sh -c를 단독으로 사용하는 간단한 예 :

sh -c "echo "You gave me $1, thanks!"" sh "apples" 

두 개의 인수를 자식 셸 스크립트에 전달합니다. 스크립트가 사용할 $0$1에 배치됩니다.

  1. 문자열 sh. 스크립트 내에서 $0로 사용할 수 있으며 내부 쉘이 오류 메시지를 출력하면이 문자열을 접두사로 표시합니다.

  2. 인수 apples는 스크립트에서 $1로 사용할 수 있으며 더 많은 인수가 있었다면 다음과 같이 사용할 수 있습니다. $2, $3 등. "$@" 목록에서도 사용할 수 있습니다. "$@"의 일부가 아닌 $0).

유용합니다. -exec와 함께 사용하면 find에서 찾은 경로 이름에서 작동하는 임의의 복잡한 스크립트를 만들 수 있습니다.

예 : 특정 파일 이름 접미사가있는 모든 일반 파일을 찾고 해당 파일 이름 접미사를 다른 접미사로 변경합니다. 여기서 접미사는 변수에 보관됩니다.

from=text # Find files that have names like something.text to=txt # Change the .text suffix to .txt find . -type f -name "*.$from" -exec sh -c "mv "$3" "${3%.$1}.$2"" sh "$from" "$to" {} ";" 

Inte 내부 rnal 스크립트, $1는 문자열 text, $2는 문자열 txt$3find에서 찾은 경로 이름입니다. 매개 변수 확장 ${3%.$1}는 경로 이름을 가져 와서 .text 접미사를 제거합니다.

또는

/basename:

find . -type f -name "*.$from" -exec sh -c " mv "$3" "$(dirname "$3")/$(basename "$3" ".$1").$2"" sh "$from" "$to" {} ";" 

또는 내부 스크립트 :

find . -type f -name "*.$from" -exec sh -c " from=$1; to=$2; pathname=$3 mv "$pathname" "$(dirname "$pathname")/$(basename "$pathname" ".$from").$to"" sh "$from" "$to" {} ";" 

이 마지막 변형에서 변수 from 및 는 외부 스크립트의 동일한 이름을 가진 변수와 다릅니다.

위는 (find 포함). find

for pathname in $( find ... ); do 

와 같은 루프에서 사용하면 오류가 발생하기 쉽고 우아하지 않습니다 (개인적 의견). 공백에서 파일 이름을 분할하고 파일 이름 globbing을 호출하며 루프의 첫 번째 반복을 실행하기 전에 쉘이 find의 전체 결과를 확장하도록합니다.

참조 :


-exec ... {} +

사용

끝의 ;는 . 이로 인해 find는 발견 된 각 경로 이름에 대해 한 번이 아니라 가능한 한 많은 인수 (찾은 경로 이름)를 사용하여 주어진 명령을 실행합니다. 이 작업을 수행하려면 {} 문자열이 + 바로 앞에 나와야합니다 .

find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec cat {} + 

여기서 find는 결과 경로 이름을 수집하고 cat를 한 번에 최대한 많이 사용합니다.

find . -type f -name "*.txt" \ -exec grep -q "hello" {} ";" \ -exec mv -t /tmp/files_with_hello/ {} + 

여기서와 마찬가지로 mv는 다음과 같이 실행됩니다. 가능한 한 몇 번. 이 마지막 예에는 coreutils의 GNU mv가 필요합니다 (-t 옵션 지원).

-exec sh -c ... {} +는 임의의 복잡한 스크립트로 경로 이름 집합을 반복하는 효율적인 방법이기도합니다.

기본은 -exec sh -c ... {} ";",하지만 이제 스크립트는 훨씬 더 긴 인수 목록을 사용합니다. 스크립트 내에서 "$@"를 반복하여 반복 할 수 있습니다.

파일 이름 접미사를 변경하는 마지막 섹션의 예 :

from=text # Find files that have names like something.text to=txt # Change the .text suffix to .txt find . -type f -name "*.$from" -exec sh -c " from=$1; to=$2 shift 2 # remove the first two arguments from the list # because in this case these are *not* pathnames # given to us by find for pathname do # or: for pathname in "$@"; do mv "$pathname" "${pathname%.$from}.$to" done" sh "$from" "$to" {} + 

-execdir

사용

-execdir도 있습니다 ( 대부분의 find 변형으로 구현되지만 표준 옵션은 아닙니다.)

이것은 -exec처럼 작동하지만 주어진 쉘 명령이 현재 작업 디렉토리로 발견 된 경로 이름의 디렉토리와 {}에는 경로없이 발견 된 경로 이름의 기본 이름이 포함됩니다 (그러나 GNU find는 여전히 기본 이름 앞에 ./, BSD find는이를 수행하지 않습니다).

예 :

find . -type f -name "*.txt" \ -execdir mv {} done-texts/{}.done \; 

그러면 발견 된 각 *.txt-파일이 파일이 있던 동일한 디렉토리에있는 기존 done-texts 하위 디렉토리 로 이동합니다. 찾았습니다 . 또한 접미사 .done를 추가하여 파일 이름을 변경합니다.

-exec 파일의 새 이름을 구성하려면 {}에서 찾은 파일의 기본 이름을 가져와야합니다. done-texts 디렉토리를 올바르게 찾으려면 {}의 디렉토리 이름도 필요합니다.

, 이와 같은 일부 작업이 더 쉬워집니다.

-execdir 를 사용하는 해당 작업 div>는 하위 셸을 사용해야합니다.

find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "$( dirname "$name" )/done-texts/$( basename "$name" ).done" done" sh {} + 

또는

find . -type f -name "*.txt" -exec sh -c " for name do mv "$name" "${name%/*}/done-texts/${name##*/}.done" done" sh {} + 

주석

  • -exec 프로그램 및 인수 를 가져와 실행합니다. 일부 쉘 명령은 프로그램과 인수로만 구성되지만 대부분은 그렇지 않습니다. 쉘 명령에는 리디렉션 및 파이프가 포함될 수 있습니다. -exec는 할 수 없습니다 (전체 find는 리디렉션 될 수 있음). 쉘 명령은 ; && if 등을 사용할 수 있습니다. -exec는 할 수 없지만 -a -o는 할 수 있습니다. 쉘 명령은 별명, 쉘 함수 또는 내장 일 수 있습니다. -exec는 할 수 없습니다. 쉘 명령은 vars를 확장 할 수 있습니다. -exec는 할 수 없습니다 (find를 실행하는 외부 셸은 할 수 있지만). 셸 명령은 매번 $(command)를 다르게 대체 할 수 있습니다. -exec는 할 수 없습니다. …
  • ‘ 여기서 쉘 명령이 잘못되었습니다. find -exec cmd arg \;는 ‘ 셸 명령 줄을 해석하기 위해 셸을 호출하지 않고 execlp("sh", "-c", "cmd arg")가 아닌 execlp("cmd", "arg")를 직접 실행합니다. 쉘은 cmd가 내장되어 있지 않은 경우 execlp("cmd", "arg")와 동일한 작업을 수행합니다.
  • 모든 것을 명확히 할 수 있습니다. -exec 뒤의 find 인수 및 최대 ; 또는 + 인수와 함께 실행할 명령을 구성하고 {} 인수의 각 인스턴스를 현재 파일 (;), + 이전의 마지막 인수로 {}가 별도의 인수로 파일 목록으로 대체되었습니다 ({} + 사례). IOW -exec; 또는 {}으로 끝나는 여러 인수를받습니다. div> +.
  • @Kusalananda는 ‘ 마지막 예제도 다음과 같은 간단한 명령으로 작동하지 않을 것입니다. find . -type f -name '*.txt' -exec sh -c "mv $1 $(dirname $1)/done-texts/$(basename $1).done" sh {} ';'?
  • @Atralb 예, 작동했을 수도 있고 마지막 코드와 동일한 효과를 보였지만 루프에서 발견 된 파일 당 한 번씩 발견 된 각 파일에 대해 shmv를 모두 실행합니다. 대용량 파일의 경우 눈에 띄게 느립니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다