컨텍스트: Catalina MacOS: .pdf 파일 세트가 포함된 디렉터리입니다. 일부 파일 이름에 공백이 포함되어 있습니다(xargs.txt에 문제가 있음)
명령줄에서: 목표는 각 .pdf 파일의 파일 이름과 페이지 번호를 반환하는 것입니다.
이 코드 조각은 파이프로 연결할 수 있는 파일 이름 목록을 반환합니다.매개변수:
find . -type f -name '*.pdf'
이 조각은 페이지 수를 반환합니다.
pdfinfo foo.pdf | grep Pages | awk '{print $2}'
pdftk foo.pdf dump_data | grep Pages | awk '{print $2}'
xargs와 함께 코드 조각을 사용하여 파일 이름에 공백이 포함될 수 있는 .pdf 파일만 처리하려면 어떻게 해야 합니까?
실패:
find . -name '*.pdf' | xargs pdfinfo |
코드 조각은 파일 이름을 인쇄하고(공백이 있는 이름은 처리할 수 없지만) 파일 이름과 같은 줄에 페이지 번호를 인쇄하지 않습니다.
find . -name '*.pdf' | xargs -I % sh -c 'echo %; pdfinfo % | grep Pages'
답변1
일부 파일 이름에 공백이 포함되어 있습니다(xargs.txt에 문제가 있음)
-print0
options find
과 -0
options 을 사용하면 됩니다 xargs
. 그들은 맨 페이지 상단에 이것을 광고해야 합니다!
find -iname '*.pdf' -print0 | xargs -0 ...
그게 다야. 이 옵션은 find
발견된 파일 이름을 개행 대신 0바이트로 구분하도록 지시합니다. 공백, 개행, 콜론 등과 달리 0바이트는아니요파일 이름에는 허용되므로 파일 이름을 구분하는 안전한 방법입니다. 구분 기호로 0바이트를 예상하도록 -0
지시합니다 .xargs
그러나 이것은 OS X이고 쉘은 아마도 잘 작동할 것이므로 find
전혀 필요하지 않습니다.
#!/usr/bin/zsh -
for pdffile in **/*.pdf(N-.) ; do
print -r -- "${pdffile}" # This is already problematic again. Your file names
# might contain newlines, spaces etc, so no easy way
# to tell where file name ends and page count starts
pdfinfo -- "${pdffile}" | grep Pages | awk '{print $2}'
done
참고하세요더블"
사용하려는 따옴표 : 래핑된 문자열이 변수 확장을 거치지 않아 문자열이 호출 프로그램에 있는 그대로(달러 기호 및 변수 이름 포함) 전달되기 '
때문에 코드가 작동하지 않습니다 . 이는 전달해야 하기 때문에 '
원하는 매개변수 이지만 실제로 변수 내용을 확장하려는 위치는 아닙니다.awk
$
블러 플로팅에 대한 대답은 정확합니다. grep을 awk
호출에 흡수할 수 있습니다. 또한 정규 표현식이 최대한 정확한지 확인해야 합니다.
또한 0으로 구분된 출력을 생성하여 "파일 이름에 공백, 줄 바꿈 및 숫자가 포함될 수 있으므로 출력에서 파일 이름이 시작하고 끝나는 위치를 알 수 없습니다" 문제를 해결할 수도 있습니다.
#!/usr/bin/zsh
for pdffile in **/*.pdf(N-.) ; do
pages=$(pdfinfo -- "${pdffile}" | awk '/^Pages:/{print $2}')
printf '%s\0\%d\0' "${pdffile}" "${pages}"
done
(PDF 파일에는 여전히 문제가 있을 수 있습니다.창조자또는생산자포함 <newline>Pages:
하지만 최소한 위의 엄격한 정규식을 사용하여 위험을 최소화했습니다.
답변2
find
명령 을 사용 -exec
하여 실행 pdfinfo
한 후 결과를 파이프하면 중간 단계 awk
없이 자체적으로 패턴 일치를 수행할 수 있습니다 .grep
find . -type f -name '*.pdf' -exec pdfinfo '{}' \; | awk '/Pages/ {print $2}'
물론 이것은 페이지 수만 제공합니다. 이제 각 파일에 대해 필요한 것을 알 수 있습니다.파일 이름 그리고총 페이지. 나는 xargs
그것이 여기서 도움이 될 것이라고 생각하지 않지만 while
루프가 그 일을 할 것입니다:
#!/bin/sh
find . -type f -name '*.pdf' | while read -r f; do
p=$(pdfinfo "$f" | awk '/Pages/ {print $2}')
printf '%s\n' "$f $p"
done
답변3
디렉터리 트리를 순회할 필요가 없는 경우 이 for
루프는 다음을 수행할 수 있습니다.
for FN in *pdf; do pdfinfo "$FN" | awk '/^Pages/ {print ARGV[2], $2; exit}' - "$FN"; done
답변4
그리고 exiftool
:
exiftool -r -ext pdf -q -p '$PageCount $Directory/$Filename' .
-r
(재귀의 경우) 와 함께 사용 -ext pdf
하면 비슷한 작업을 수행합니다 find . -name '*.pdf'
.
프리젠테이션용으로 좋습니다.
쉘 루프와 같이 사후 처리 가능한 출력의 경우 NUL로 구분된 출력 형식을 사용하는 것이 좋습니다.
exiftool -r -ext pdf -q -if 'print "$PageCount/$Directory/$Filename\0";0' . |
while IFS=/ read -rd '' page file; do
something with "$page" and "$file"
done
( zsh
또는 가정 bash -O lastpipe
)
또는 json, xml 또는 php1과 같이 지원하는 일부 직렬화 형식:
$ exiftool -r -ext pdf -q -j -PageCount .
[{
"SourceFile": "./a.pdf",
"PageCount": 4
},
{
"SourceFile": "./a\nb.pdf",
"PageCount": 4
}]
$ exiftool -r -ext pdf -q -X -PageCount .
<?xml version='1.0' encoding='UTF-8'?>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about='./a.pdf'
xmlns:et='http://ns.exiftool.ca/1.0/' et:toolkit='Image::ExifTool 11.88'
xmlns:PDF='http://ns.exiftool.ca/PDF/PDF/1.0/'>
<PDF:PageCount>4</PDF:PageCount>
</rdf:Description>
<rdf:Description rdf:about='./a
b.pdf'
xmlns:et='http://ns.exiftool.ca/1.0/' et:toolkit='Image::ExifTool 11.88'
xmlns:PDF='http://ns.exiftool.ca/PDF/PDF/1.0/'>
<PDF:PageCount>4</PDF:PageCount>
</rdf:Description>
</rdf:RDF>
exiftool -r -ext pdf -q -php -PageCount .
Array(Array(
"SourceFile" => "./a.pdf",
"PageCount" => 4
),
Array(
"SourceFile" => "./a\nb.pdf",
"PageCount" => 4
));
(여기서는 개행 문자가 포함된 파일 이름을 예로 사용합니다.)
그러나 JSON 및 XML은 UTF-8로 적절하게 인코딩된 텍스트로 구성된 파일 이름에서만 작동하며 이는 이러한 형식의 제한 사항입니다.