ディレクトリ内の各PDF文書のファイル名とページ番号を返します。

ディレクトリ内の各PDF文書のファイル名とページ番号を返します。

コンテキスト: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に問題があります)

-print0optionsfind-0optionsを使用してくださいxargs。彼らはマンページの上部にこれを宣伝する必要があります!

find -iname '*.pdf' -print0 | xargs -0 ...

それはすべてです。このオプションは、find見つかったファイル名を改行ではなくゼロバイトで区切るように指示します。スペース、改行、コロンなどとは異なり、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呼び出しに吸収できます。また、正規表現ができるだけ正確であることを確認する必要があります。

また、ゼロで区切られた出力を生成して、「ファイル名にスペース、改行、数字を含めることができるため、出力でファイル名が開始および終了する場所がわからない」という問題を解決することもできます。

#!/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で適切にエンコードされたテキストで構成されたファイル名でのみ機能します。これはこれらの形式の制限です。

関連情報