Bash

嘗試通過循環遞歸地使用 ghostscript 壓縮 pdf 時出錯

  • January 14, 2019

我打算遞歸壓縮文件夾中的幾千個 PDF 文件。

我嘗試了以下循環:

#!/bin/bash
find "/home/user/original" -type f -name *.pdf | while read -r file
do
 gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress -dNOPAUSE -dBATCH -dQUIET -sOutputFile="/home/user/processed$file" "$file"
done

(處理 $ file is used because $ 文件在開始時帶有 / 並且我也嘗試過處理/$file)

無論如何,執行循環會產生以下錯誤:

GPL Ghostscript 9.26: **** Could not open the file /home/user/processed/home/user/original/test001.pdf .
**** Unable to open the initial device, quitting.

出於某種原因,它在 path/to/output/path/to/input 中尋找 pdf。我嘗試更改為 ./ 連結而不是 / 但無濟於事。

如果我自己執行以下命令,它會很好地輸出壓縮的 pdf

gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress -dNOPAUSE -dBATCH -dQUIET -sOutputFile="/home/user/processed/output.pdf" "input.pdf"

任何想法為什麼循環不起作用?

PS所有目錄現在都是777,以確保沒有任何權限錯誤

經過幾次測試,我觀察到 Ghostscript 的以下行為。當您將輸出文件指定為/home/user/processed/home/user/original/test001.pdf時,該gs命令期望通向文件 ( /home/user/processed/home/user/original/) 的路徑已經存在。由於源中的文件夾結構目前在目標中不存在,因此該命令會引發錯誤並顯示它無法打開目標文件。

要解決此問題,您可以首先使用以下命令重新創建文件夾結構:

cd /home/user/original
find . -type d -exec mkdir -p -- /home/user/processed/{} \;

完成後,您可以執行腳本來生成 PDF 文件。我可以使用您的gs命令生成 PDF 文件,所以我假設它沒有進一步的問題。

腳本完成後,如果您懷疑目標位置存在空目錄,並想擺脫它們,請使用以下 find 命令:

find /home/user/processed/ -type d -empty -delete

問題

預設情況下,find執行-print操作:

 -print

真的; 在標準輸出上列印完整的文件名,後跟換行符。

“完整文件名”意味著您將看到每個文件的絕對路徑:

/home/user/original/test001.pdf
/home/user/original/test002.pdf
...
/home/user/original/test999.pdf

所以當你使用

gs -sOutputFile="/home/user/processed$file"

…在循環內,變數$filecontains /home/user/original/test001.pdf,整個表達式擴展為​​連接的兩條路徑:

gs -sOutputFile="/home/user/processed/home/user/original/test001.pdf"

您看到的錯誤消息反映了這一點:

Could not open the file /home/user/processed/home/user/original/test001.pdf

使用基本名稱

如果您只想要文件的基本名稱(因為所有文件都在同一個源文件夾中),您可以告訴find使用不同的輸出格式。

find "/home/user/original" -type f -name *.pdf -printf '%f\n'
   -printf format

真的; 在標準輸出上列印格式,解釋“\”轉義和“%”指令。

$$ … $$

        \n     Newline.

        %f     File's name with any leading directories removed (only
                 the last element).

使用相對名稱

或者(如果輸入文件位於不同的目錄中),您將需要修剪一些目錄路徑。你可以使案例如。cut為了那個原因:

find "/home/user/original" -type f -name *.pdf | cut -d/ -f5- | while read -r file
do
   gs [...] -sOutputFile="/home/user/processed/$file" "/home/user/original/$file"

這將刪除所有內容,包括/輸入的第 4 個。但是,它不會處理新輸出目錄的創建以匹配輸入樹的結構。

引用自:https://unix.stackexchange.com/questions/494425