古人云:天下文章一大抄。整个三月,浙江大学 CS 开题报告热火朝天,其中各种纠结与不解、各种困惑与混乱、各种 Word/TeX 模版纷争,不再详述。23 号提交论文,但时至此刻,我刚刚 Google Translate 了一片水文搞定了外文翻译,修改了学院 bug 百出的 LaTeX 模版,搞定了开题报告的格式,至于剩下的 3500 字,尚无着落,痛苦不堪,心慌也。
废话少说,今天晚上去万方数据库校内镜像下载学位论文,岂知万方这个财主极其抠门猥琐,不但很多有价值的学术论文无法下载,可以下载的论文也是一个 zip 压缩包,然后里面几十到上百个 PDF 不等……看一篇完整的学位论文要打开几十个 PDF,莫说是我,就是我的 x201i,也该累死了……
一个典型的万方学位论文 zip 压缩包目录结构如下:
lox >>> tree IPTV机顶盒 GUI 子系统的研究与实现
IPTV 机顶盒 GUI 子系统的研究与实现
├── default.htm
├── Images
│ ├── ball.gif
lox >>> tree -L 3 -p -N | grep '\[d'
└── [drwxrwxr-x] wanfang
├── [drwxrwxr-x] IPTV机顶盒 GUI 子系统的研究与实现
│ ├── [drwxrwxr-x] Images
│ └── [drwxrwxr-x] Paper
├── [drwxrwxr-x] Tools设计与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于 QtEmbedded 的图形用户界面移植
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于嵌入式 Linux 智能手机 GUI 平台的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于消息通信机制嵌入式 GUI 的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式 Linux 图形用户界面的研究与开发
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式 uGUI 的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式系统轻量化 GUI 框架的设计与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
└── [drwxrwxr-x] 面向数字家电产品的 GUI 框架的设计与实现
├── [drwxrwxr-x] Images
├── [drwxrwxr-x] Paper
│ ├── bg.gif
│ ├── folder.gif
│ ├── H.gif
│ ├── I.gif
│ ├── L.gif
│ ├── nfolder.gif
│ ├── ofolder.gif
lox >>> tree IPTV机顶盒 GUI 子系统的研究与实现
IPTV 机顶盒 GUI 子系统的研究与实现
├── default.htm
├── Images
│ ├── ball.gif
│ ├── bg.gif
│ ├── folder.gif
│ ├── H.gif
│ ├── I.gif
│ ├── L.gif
│ ├── nfolder.gif
│ ├── ofolder.gif
│ └── T.gif
└── Paper
└── pdf
├── d0447950001.pdf
├── d0447950002.pdf
├── d0447950003.pdf
├── d0447950004.pdf
├── d0447950005.pdf
├── d0447950006.pdf
├── d0447950007.pdf
├── d0447950008.pdf
├── d0447950009.pdf
├── d044795wz.pdf
├── d044795zye.pdf
├── fm.htm
├── index.htm
├── iptv.pdf
├── left.htm
├── ml.htm
└── single_merged_pdf.pdf
3 directories, 28 files
所有的 PDF 文档在 ./Paper/pdf 目录下,并且必有一个 xxxxwz.pdf 和一个 xxxxzye.pdf 文件,剩下的 PDF 文件基本上内容顺序和编号顺序一致,但是不排除有页码重叠的状况。
想到的办法就是找 CLI 工具,将这些 PDF 合并成一份完整的论文。Arch Linux 下: pacman -Ss pdf
,结合 Google,得到几个相关的 PDF 工具:
- pdfedit
- ghostscript
- pdftk
- poppler
PDFedit 是图形化的 PDF edit(编辑)工具,显然不符合 CLI 自动化处理的要求。而且看界面是基于 Qt 3.x 的,编辑功能应该是很强大的。具体可以看 PDFedit 的 Screenshots。不过这与本文无关了。
ghostscript is an interpreter for the PostScript language。linuxtoy 给出了一种合并 PDF 方法,我尝试了一下,但是万方本身的 PDF 是加密的,直接转换会出现莫名其妙的错误,所以这种方法最终失败。
PDFtk 是一个十分强大的 PDF 工具,按照官方的说法,PDFtk 可以用来:
- Merge PDF Documents
- Split PDF Pages into a New Document
- Rotate PDF Pages or Documents
- Decrypt Input as Necessary (Password Required)
- Encrypt Output as Desired
- Fill PDF Forms with FDF Data or XFDF Data and/or Flatten Forms
- Apply a Background Watermark or a Foreground Stamp
- Report on PDF Metrics such as Metadata, Bookmarks, and Page Labels
- Update PDF Metadata
- Attach Files to PDF Pages or the PDF Document
- Unpack PDF Attachments
- Burst a PDF Document into Single Pages
- Uncompress and Re-Compress Page Streams
- Repair Corrupted PDF (Where Possible)
可以用 pdftk 1.pdf 2.pdf 3.pdf && cat output 123.pdf
的方式来合并 PDF,但是由于万方 PDF 的特殊加密,用 PDFtk 合并时,会出现 "OWNER PASSWORD REQUIRED" 的失败提示。所以成功合并 PDF 的最关键问题就是去掉万方 PDF 加密。
幸运的是,我在 townx 找到了解决方法,感谢万能的 Google。剩下的任务,就是 shell script 的天地了。
至于 shell Script,已经好久没有摆弄,很多写法已经生疏,好在半年前在华数淘宝写的脚本还在,打开浏览了下,照葫芦画瓢,倒也没有遇到太大困难。完整的脚本如下:
#!/usr/bin/env bash
################################################################################
# Purpose: Merge pdf file downloaded from Wanfang dissertation database
# (http://g.wanfangdata.com.cn/)
# Author: Xiao Hanyu(xiaohanyu1988@gmail.com)
# Depends:
# pdftk: merge multiple pdf files, pdftk is also a useful pdf
# manipulation tools
# ps2pdf/pdftops: pdf --> ps then ps --> pdf to remove encryption
################################################################################
function usage
{
cat << EOF
`basename $0`: A utility to merge encryted pdf files into one single pdf
Usage: `basename $0` [Options]
Example:
`basename $0` -f "file1.pdf file2.pdf" -o merged.pdf
`basename $0` -d input_pdf_dir -o merged.pdf
`basename $0` -d input_pdf_dir
Options:
-f: set the input pdf file list
-d: set the input pdf directory
-o: set the output pdf filename
-h: show this help
EOF
}
function merge_pdfs
{
echo "######## Convert begin!! ########"
for pdf in $pdf_list
do
## do not use pdf_name = `basename $pdf .pdf`
## since basename will remove the directory prefix of $pdf
pdf_name=`echo $pdf | sed -e "s/\.pdf//"`
## add some animation ^_^
echo -n "$pdf_name.pdf ---->> $pdf_name.ps "
pdftops $pdf_name.pdf $pdf_name.ps
echo "---->> $pdf_name.pdf"
ps2pdf $pdf_name.ps $pdf_name.pdf
rm -rf $pdf_name.ps
done
echo "######## Convert end!! ########"
echo "######## Merge begin!! ########"
pdftk $pdf_list cat output $pdf_merge
echo "######## Merge success, open $pdf_merge to see the result. Bye!! ########"
}
while getopts "d:f:o:h" arg
do
case $arg in
d)
pdf_dir=$OPTARG
pdf_list=`ls $pdf_dir/*pdf`
;;
f)
pdf_list=$OPTARG
;;
o)
pdf_merge=$OPTARG
;;
h)
usage
exit 0
;;
?)
echo "!!Wrong command options"
usage
exit 1
;;
esac
done
# if pdf_dir is not set yet, then it's set to default(that is, current directory)
pdf_dir=${pdf_dir:-"."}
# set default output pdf filename, plus $pdf_dir prefix
pdf_merge="${pdf_dir}/${pdf_merge:-"single_merged_pdf.pdf"}"
merge_pdfs
脚本结构还是很简单的:
- 参数解析采用 bash 内置的
getopts
,暂时只支持短选项 - 有一个帮助说明函数
function usage{}
- 关键函数是
function merge_pdfs{}
,尤其需要注意目录名和文件名的处理
调用方法如 function usage{}
里面所示:
./wanfang_pdf_merge.sh -d pdf_dir
./wanfang_pdf_merge.sh -d . -o merged_pdf.pdf
./wanfang_pdf_merge.sh -f "dir1/pdf1.pdf dir2/pdf2.pdf" -o output/merged_pdf.pdf
测试:
在这个基础脚本上进一步封装下,比如,对于如下的目录结构:
lox >>> tree -L 3 -p -N | grep '\[d'
└── [drwxrwxr-x] wanfang
├── [drwxrwxr-x] IPTV机顶盒 GUI 子系统的研究与实现
│ ├── [drwxrwxr-x] Images
│ └── [drwxrwxr-x] Paper
├── [drwxrwxr-x] Tools设计与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于 QtEmbedded 的图形用户界面移植
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于嵌入式 Linux 智能手机 GUI 平台的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 基于消息通信机制嵌入式 GUI 的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式 Linux 图形用户界面的研究与开发
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式 uGUI 的研究与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
├── [drwxrwxr-x] 嵌入式系统轻量化 GUI 框架的设计与实现
│ ├── [drwxrwxr-x] Images
│ ├── [drwxrwxr-x] Paper
└── [drwxrwxr-x] 面向数字家电产品的 GUI 框架的设计与实现
├── [drwxrwxr-x] Images
├── [drwxrwxr-x] Paper
我们的封装脚本命令如下:
for pdf_dir in `tree wanfang -ipNf | grep '\[d' | grep 'pdf' | awk '{print $2}'`
do
~/tools/wanfang_pdf_merge.sh -d $pdf_dir
done
接下来喝咖啡!!!
咖啡喝完后,我们来看一下结果:
lox >>> tree -ipNf | grep 'single'
[-rw-rw-r--] ./wanfang/IPTV机顶盒 GUI 子系统的研究与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/Tools 设计与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/Tools 设计与实现/Paper/pdf/single_merged_pdf.ps
[-rw-rw-r--] ./wanfang/基于 QtEmbedded 的图形用户界面移植/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/基于嵌入式 Linux 智能手机 GUI 平台的研究与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/基于消息通信机制嵌入式 GUI 的研究与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/嵌入式 Linux 图形用户界面的研究与开发/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/嵌入式 uGUI 的研究与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/嵌入式系统轻量化 GUI 框架的设计与实现/Paper/pdf/single_merged_pdf.pdf
[-rw-rw-r--] ./wanfang/面向数字家电产品的 GUI 框架的设计与实现/Paper/pdf/single_merged_pdf.pdf
大功告成!!!
接下来的任务是:
写论文!!!!!!!!!!