> 이후에는 사용할 수 없는 exec '{}' 찾기

> 이후에는 사용할 수 없는 exec '{}' 찾기

Exec을 사용하면 모든 매개변수를 한 번에 전달 {} +하거나 다음을 사용하여 하나씩 전달할 수 있습니다.{} \;

이제 모든 이름을 바꾸고 싶다고 가정 해 보겠습니다.JPEG, 이렇게 하는 데에는 문제가 없습니다.

find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec mv '{}' '{}'.new \;

그러나 출력을 리디렉션해야 하는 경우 '{}'리디렉션 후에는 액세스할 수 없습니다.

find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec cjpeg -quality 80 '{}' > optimized_'{}' \;

이것은 작동하지 않습니다. for 루프를 사용하고 find를 사용하기 전에 출력을 변수에 저장해야 합니다. 현실을 직시하자, 그것은 번거로운 일이다.

for f in `find . \( -name '*.jpg' -o -name '*.jpeg' \)`; do cjpeg -quality 80 $f > optimized_$f; done;

그럼 더 좋은 방법이 있나요?

답변1

bash -c명령 에서 사용 find -exec하고 bash 명령과 함께 위치 인수를 사용할 수 있습니다.

find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec bash -c 'cjpeg -quality 80 "$1" > "$(dirname "$1")/optimized_$(basename "$1")"' sh {} \;

{}이 방법이 제공됩니다 $1.

sh{}여기에 사용된 문자열은 내부 쉘에 "이름"을 알리기 전의 오류 메시지에 사용됩니다. 이에 대해서는 다음에서 더 자세히 논의됩니다.stackoverflow에 대한 이 답변.

답변2

답이 있습니다 (https://unix.stackexchange.com/a/481687/4778), 하지만 그게 이유입니다.

리디렉션 >, 파이핑 |$확장은 모두 명령을 실행하기 전에 셸에서 수행됩니다. 따라서 optimized_{}시작하기 전에 stdout이 로 리디렉션됩니다.find

답변3

현재 쉘이 이를 해석하는 것을 방지하려면 리디렉션이 필요합니다.
그러나 이를 인용하면 명령의 출력이 리디렉션되는 것을 방지할 수도 있습니다.
알려진 해결책은 셸을 호출하는 것입니다.

find . -name '*.jpg' -exec sh -c 'echo "$1" >"$1".new' called_shell '{}' \;

이 경우 리디렉션( >)은 현재 셸에서 참조되며 호출 셸 내에서 정상적으로 작동합니다. 서브쉘( )에 대한 인수(이름)로 사용됩니다 called_shell.$0sh

파일 이름에 접미사를 추가하면 잘 작동하지만 접두사를 사용하면 잘 작동하지 않습니다. 접두사가 작동하도록 하려면 ./파일 이름 앞의 찾기를 제거 ${1#./}하고 해당 -execdir옵션을 사용해야 합니다.

-iname이 옵션을 사용하여 *.JPG이름이 지정되거나 다른 변형이 있는 파일 도 포함할 수도 있고 그렇지 않을 수도 있습니다 .*.JpG

find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
     cjpeg -quality 80 "$1" > optimized_"${1#./}"
     ' called_shell '{}' \;

for f do … ; done그리고 끝에 루프( )와 a를 추가하여 파일당 한 번이 아닌 디렉터리당 한 번 셸을 호출 할 수도 있고 그렇지 않을 수도 있습니다 .+

find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
     for f; do cjpeg -quality 80 "$f" > optimized_"${f#./}"; done
     ' called_shell '{}' \+

마지막으로 cjpeg파일에 직접 쓸 수 있으면 리디렉션이 방지됩니다.

find . \( -iname '*.jpg' -o -iname '*.jpeg' \) -execdir sh -c '
     for f; do cjpeg -quality 80 "$f" -outfile optimized_"${f#./}"; done
     ' called_shell '{}' \+

답변4

스크립트 cjq80을 생성합니다:

#!/bin/bash
cjpeg -quality 80 "$1" > "${1%/*}"/optimized_"${1##*/}"

실행 가능하게 만들어라

chmod u+x cjq80

-exec에서 사용하세요.

find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec cjq80 '{}' \;

관련 정보