find -exec와 함께 명령 대체를 사용하는 방법은 무엇입니까?

find -exec와 함께 명령 대체를 사용하는 방법은 무엇입니까?

다음을 사용하면 basename {} .txt작동합니다 .

find . -iname "*.txt" -exec basename {} .txt \;

xxx대신에 인쇄됩니다 ./xxx.txt. 옵션을 사용하면 $(basename {} .txt)실패 -exec합니다.

find . -iname "*.txt" -exec echo "$(basename {} .txt)" \;

그냥 인쇄될 거예요./xxx.txt

이 문제를 어떻게 해결할 수 있나요? $(basename {} .txt)다른 cmd의 매개변수 로 사용할 수 있기를 바랍니다 . 조작이나 파이핑을 위해 xargs를 사용해야 합니까 sh -c?-exec basename {} \;

답변1

노력하다:

find -iname "*.txt" -exec sh -c 'for f do basename -- "$f" .txt;done' sh {} +

첫 번째 명령은 $(...)하위 쉘에서 실행될 때 {}리터럴로 처리되기 때문에 실패합니다. 따라서 basename {} .txt돌아 오면 {}다음과 find같습니다.

find . -iname "*.txt" -exec echo {} \;

어떤 인쇄 파일 이름이 일치합니까?

답변2

$()및 작은따옴표를 사용하는 경우에도 sh -c명령 대체를 사용할 수 있습니다.

find . -iname "*.txt" -exec sh -c 'echo "$(basename {} .txt)"' \;

작은따옴표는 메인 쉘이 그 안에 있는 하위 명령을 실행하는 것을 방지하므로 $()다음을 전달할 수 있습니다.sh -c 뒤쪽에명령 이 파일 이름으로 find대체되었습니다 . {}바라보다스택 오버플로에 대한 이 답변더 자세한 설명을 위해.

$()파일 이름에 공백을 처리하기 위해 큰따옴표를 추가할 수도 있습니다 .

find . -iname "*.txt" -exec sh -c 'echo "$(basename "{}" .txt)"' \;

답변3

xargs대신 bash 파이프와 명령을 사용하는 다른 방법이 있습니다 .

    find . -iname '*.txt' | xargs -L1 -I{} basename "{}"

xargs위 명령 에서 :

매개변수는 -L1한 줄씩 실행되는 명령줄의 출력을 나타냅니다 find.

이 매개변수는 bash 토큰화(파일 이름에 공백이 포함된 경우)를 방지하기 위해 명령 출력을 큰따옴표로 묶기 -I{}위한 것입니다 .find

답변4

파이핑이 더 쉽기 때문에(입력, 기억, 읽기 등) @an9wer에 동의합니다. 예를 들어 posix xargs를 준수하고 구분 기호로 nil 문자를 사용하려고 노력하지만, alpine의 xargs에는 태그가 없습니다 -L1. 및 명령을 사용하려면 find에 nil을 명시적으로 표시하세요 xargs. 임시 명령 실행에 대해 이야기하는 경우 이를 무시하십시오. 그러나 이것이 프로덕션 환경이 아닌 환경에서 개발된 스크립트이고 프로덕션 환경이 절대 변경되지 않을 것이라고 가정하면 이는 실제로 큰 문제입니다.

@an9swer와 동일하지만 nil 문자를 구분 기호로 사용하고 -n플래그를 사용하여 결과를 한 번에 하나씩 인수로 제공합니다 basename. 또한 템플릿 플래그 -I는 추론되고 기본 동작이므로 필요하지 않습니다 .

find . -iname '*.txt' -print0 | xargs -0 -n1 -- basename

위의 또 다른 장점은 xargs를 사용하면 전달된 명령문을 병렬로 실행할 수 있다는 것입니다. 즉, 일부 다운스트림 프로세스에 공급해야 하는 코어 수까지 위의 명령문을 병렬로 실행할 수 있습니다. 거의 무한한 수의 파일로 작업하거나 작업 흐름 최적화가 중요한 경우 이는 매우 큰 이점입니다.

네, 저는 좀 과시하는 편이지만 (가끔) 얌전할 수도 있으니 괜찮습니다.

관련 정보