次の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
.jpg
PDFファイル名の一部を削除する方法は?言い換えれば、私はそれを望ん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
結果のデフォルト名(ファイル名サフィックスなし)の「root」を抽出し、それを.png
最後に追加します。
上記のすべての変更は次のとおりです。現在のディレクトリに出力を書き込む、JPEGファイルがある場所ならどこでも可能です。すべてのJPEGファイルが現在のディレクトリにある場合、これはまったく必要ではなく、find
ワイルドカードパターンの拡張に単純なループを使用できます*.jpg
。
for pathname in ./*.jpg; do
img2pdf --output "${pathname%.jpg}.png" "$pathname"
done
パラメータ置換は${pathname%.jpg}
値の末尾から削除されます。この代替品を使用したい場合があります.jpg
$pathname
変える basename
JPEGファイルが見つかった元のディレクトリに出力を書きたい場合(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'
構文が良く見える場合は、お気に入りのシェルにパイプしてください。