-exec 명령 옵션 및 basename 찾기

-exec 명령 옵션 및 basename 찾기

다음 JPEG 파일이 있습니다.

$ ls -l
-rw-r--r-- 1 user group 384065 janv. 21 12:10 CamScanner 01-10-2022 14.54.jpg
-rw-r--r-- 1 user group 200892 janv. 10 14:55 CamScanner 01-10-2022 14.55.jpg
-rw-r--r-- 1 user group 283821 janv. 21 12:10 CamScanner 01-10-2022 14.56.jpg

$ img2pdf각 이미지를 PDF 파일로 변환하는 데 사용합니다 . 이 작업을 수행할 수 있어야 합니다.

$ find . -type f -name "*.jpg" -exec img2pdf "{}" --output $(basename {} .jpg).pdf \;

결과:

$ ls -l *.pdf
-rw-r--r-- 1 user group 385060 janv. 21 13:06 CamScanner 01-10-2022 14.54.jpg.pdf
-rw-r--r-- 1 user group 201887 janv. 21 13:06 CamScanner 01-10-2022 14.55.jpg.pdf
-rw-r--r-- 1 user group 284816 janv. 21 13:06 CamScanner 01-10-2022 14.56.jpg.pdf

.jpgPDF 파일 이름의 일부를 제거하는 방법은 무엇입니까 ? 즉, 나는 그것을 원하고 CamScanner 01-10-2022 14.54.pdf원하지 않는다 CamScanner 01-10-2022 14.54.jpg.pdf.

단독으로 사용하면 $ basename filename .extension확장자 없이 파일 이름을 인쇄합니다. 예:

$ basename CamScanner\ 01-10-2022\ 14.54.jpg .jpg
CamScanner 01-10-2022 14.54

$ find하지만 내 명령에서 구문이 작동하지 않는 것 같습니다. 이유를 아시나요?

참고: 이 부품은 동일한 부품 $ img2pdf으로 교체해도 제거되지 않습니다 .$ echo$ basename.jpg

$ find . -type f -name "*.jpg" -exec echo $(basename {} .jpg).pdf \;
./CamScanner 01-10-2022 14.56.jpg.pdf
./CamScanner 01-10-2022 14.55.jpg.pdf
./CamScanner 01-10-2022 14.54.jpg.pdf

답변1

명령의 문제점 find은 주변 명령 대체가 basename쉘에 의해 수행된다는 것입니다앞으로심지어 실행이 시작됩니다 find( find매개변수가 무엇인지 평가하는 단계로).

선택적 인수가 있는 간단한 유틸리티 이외의 다른 것을 실행해야 할 때마다 find(예를 들어 질문에서와 같이 파이프, 리디렉션 또는 확장을 수행해야 하는 경우) 다음 작업을 수행하려면 셸을 사용해야 합니다.

find . -type f -name '*.jpg' \
    -exec sh -c 'img2pdf --output "$(basename "$1" .jpg).pdf" "$1"' sh {} \;

또는 더 효율적으로(각 호출은 sh -c발견된 경로 이름 일괄 처리)

find . -type f -name '*.jpg' -exec sh -c '
    for pathname do
        img2pdf --output "$(basename "$pathname" .jpg).pdf" "$pathname"
    done' sh {} +

또는 zsh,

for pathname in ./**/*.jpg(.DN); do
    img2pdf --output $pathname:t:r.png $pathname
done

이는 globbing 한정자를 사용하여 .DN일반 파일만 일치시키고( .) 숨겨진 이름 일치를 허용하며( D) 일치하는 항목이 없으면 패턴을 제거합니다( N). 그런 다음 :t수정자를 사용하여 "tail"(파일 이름 구성 요소)을 추출 $pathname하고 :r결과 기본 이름(파일 이름 접미사 없음)의 "루트"를 추출한 다음 이를 .png끝에 추가합니다.

위의 모든 변경사항은 다음과 같습니다.현재 디렉터리에 출력 쓰기, JPEG 파일이 있는 곳이면 어디든 가능합니다. 모든 JPEG 파일이 현재 디렉토리에 있는 경우 이는 전혀 필요하지 않으며 find와일드카드 패턴 확장 시 간단한 루프를 사용할 수 있습니다 *.jpg.

for pathname in ./*.jpg; do
    img2pdf --output "${pathname%.jpg}.png" "$pathname"
done

매개변수 대체는 ${pathname%.jpg}값 끝에서 제거됩니다. 이 대체품을 사용하고 싶을 수도 있습니다.jpg$pathname바꾸다 basenameJPEG 파일이 발견된 원래 디렉터리에 출력을 쓰려는 경우( find예: 다음과 같은 여러 디렉터리를 사용하는 경우)

find . -type f -name '*.jpg' -exec sh -c '
    for pathname do
        img2pdf --output "${pathname%.jpg}.pdf" "$pathname"
    done' sh {} +

또한보십시오:

답변2

실용적인 관점에서 질문 끝에 설명된 상태에 도달하면 다음과 같습니다.

./CamScanner 01-10-2022 14.56.jpg.pdf
./CamScanner 01-10-2022 14.55.jpg.pdf
./CamScanner 01-10-2022 14.54.jpg.pdf

rename선택적으로 다음을 사용하여 원하는 최종 파일 이름을 얻을 수 있습니다 .

~ rename 's/jpg.pdf/pdf/'

답변3

@Ulrich Schwarz의 의견이 정확합니다. 완료하려면 따옴표나 작은따옴표로 묶인 파일 이름이 없다고 가정해 보겠습니다.

.jpg 없이 기본 이름만 출력하도록 구문을 조정한 다음, find적절한 경우 확장자를 사용하여 구문을 awk다시 작성합니다 img2pdf..jpg.pdf

find명령은 기본 이름만 출력합니다.

$ find . -type f -name "*.jpg" -exec basename {} .jpg \;
CamScanner 01-10-2022 14.56
CamScanner 01-10-2022 14.55
CamScanner 01-10-2022 14.54

이제 이러한 기본 이름을 전달 awk하고 awk가 올바른 구문을 구성하도록 합니다 img2pdf.

$  find . -type f -name "*.jpg" -exec basename {} .jpg \; | \
    awk '{print "cp -vp '\''" $0 ".jpg'\'' --output '\''" $0 ".pdf'\''"}'
img2pdf 'CamScanner 01-10-2022 14.56.jpg' --output 'CamScanner 01-10-2022 14.56.pdf'
img2pdf 'CamScanner 01-10-2022 14.55.jpg' --output 'CamScanner 01-10-2022 14.55.pdf'
img2pdf 'CamScanner 01-10-2022 14.54.jpg' --output 'CamScanner 01-10-2022 14.54.pdf'

구문이 괜찮아 보이면 즐겨 사용하는 셸에 파이프하세요.

관련 정보