将目录内指定扩展名的所有文件转换为pdf,对所有子目录递归
Convert all files of a specified extension within a directory to pdf, recursively for all sub-directories
我正在使用以下代码(来自 this answer)将当前目录中的所有 CPP 文件转换为名为 code.pdf 的文件并且运行良好:
find . -name "*.cpp" -print0 | xargs -0 enscript -Ecpp -MLetter -fCourier8 -o - | ps2pdf - code.pdf
我想将此脚本改进为:
让它成为一个 .sh 文件,可以带一个参数指定
扩展而不是将其硬编码为 CPP;
有运行递归,访问当前目录的所有子目录;
对于遇到的每个子目录,将指定扩展名的所有文件转换为名为 $NameOfDirectory$.PDF 的单个 PDF,并放置在该子目录中;
首先,如果我没理解错的话,您使用的实际上是错误的 - find
将从所有子目录中检索文件。要递归工作,只从当前目录获取文件(我将其命名为 do.bash
):
#!/bin/bash
ext=
if ls *.$ext &> /dev/null; then
enscript -Ecpp -MLetter -fCourier8 -o - *.$ext | ps2pdf - $(basename $(pwd)).pdf
fi
for subdir in */; do
if [ "$subdir" == "*/" ]; then break; fi
cd $subdir
/path/to/do.bash $ext
cd ../
done
检查是为了确保具有扩展名的文件或子目录确实存在。此脚本在当前目录上运行,并递归调用自身 - 如果您不想要完整路径,请将其放入您的 PATH 列表中,尽管完整路径很好。
首先,如果我没有理解错的话,这个要求:
For each subdirectory encountered, convert all files of the specified extension to a single PDF that is named $NameOfDirectory$.PDF
不明智。如果这意味着,比方说,a/b/c/*.cpp
被写入 ./c.pdf
,那么如果您还有 a/d/x/c/*.cpp
,您就完蛋了,因为两个目录的内容都映射到同一个 PDF。这也意味着 *.cpp
(即 current 目录中的 CPP 文件)被写入名为 ./..pdf
.
的文件
像这样的东西,它根据所需的扩展名命名 PDF 并将其放在每个子目录中与源文件一起,没有这些问题:
#!/usr/bin/env bash
# USAGE: ext2pdf [<ext> [<root_dir>]]
# DEFAULTS: <ext> = cpp
# <root_dir> = .
ext="${1:-cpp}"
rootdir="${2:-.}"
shopt -s nullglob
find "$rootdir" -type d | while read d; do
# With "nullglob", this loop only runs if any $d/*.$ext files exist
for f in "$d"/*.${ext}; do
out="$d/$ext".pdf
# NOTE: Uncomment the following line instead if you want to risk name collisions
#out="${rootdir}/$(basename "$d")".pdf
enscript -Ecpp -MLetter -fCourier8 -o - "$d"/*.${ext} | ps2pdf - "$out"
break # We only want this to run once
done
done
我正在使用以下代码(来自 this answer)将当前目录中的所有 CPP 文件转换为名为 code.pdf 的文件并且运行良好:
find . -name "*.cpp" -print0 | xargs -0 enscript -Ecpp -MLetter -fCourier8 -o - | ps2pdf - code.pdf
我想将此脚本改进为:
让它成为一个 .sh 文件,可以带一个参数指定 扩展而不是将其硬编码为 CPP;
有运行递归,访问当前目录的所有子目录;
对于遇到的每个子目录,将指定扩展名的所有文件转换为名为 $NameOfDirectory$.PDF 的单个 PDF,并放置在该子目录中;
首先,如果我没理解错的话,您使用的实际上是错误的 - find
将从所有子目录中检索文件。要递归工作,只从当前目录获取文件(我将其命名为 do.bash
):
#!/bin/bash
ext=
if ls *.$ext &> /dev/null; then
enscript -Ecpp -MLetter -fCourier8 -o - *.$ext | ps2pdf - $(basename $(pwd)).pdf
fi
for subdir in */; do
if [ "$subdir" == "*/" ]; then break; fi
cd $subdir
/path/to/do.bash $ext
cd ../
done
检查是为了确保具有扩展名的文件或子目录确实存在。此脚本在当前目录上运行,并递归调用自身 - 如果您不想要完整路径,请将其放入您的 PATH 列表中,尽管完整路径很好。
首先,如果我没有理解错的话,这个要求:
For each subdirectory encountered, convert all files of the specified extension to a single PDF that is named $NameOfDirectory$.PDF
不明智。如果这意味着,比方说,a/b/c/*.cpp
被写入 ./c.pdf
,那么如果您还有 a/d/x/c/*.cpp
,您就完蛋了,因为两个目录的内容都映射到同一个 PDF。这也意味着 *.cpp
(即 current 目录中的 CPP 文件)被写入名为 ./..pdf
.
像这样的东西,它根据所需的扩展名命名 PDF 并将其放在每个子目录中与源文件一起,没有这些问题:
#!/usr/bin/env bash
# USAGE: ext2pdf [<ext> [<root_dir>]]
# DEFAULTS: <ext> = cpp
# <root_dir> = .
ext="${1:-cpp}"
rootdir="${2:-.}"
shopt -s nullglob
find "$rootdir" -type d | while read d; do
# With "nullglob", this loop only runs if any $d/*.$ext files exist
for f in "$d"/*.${ext}; do
out="$d/$ext".pdf
# NOTE: Uncomment the following line instead if you want to risk name collisions
#out="${rootdir}/$(basename "$d")".pdf
enscript -Ecpp -MLetter -fCourier8 -o - "$d"/*.${ext} | ps2pdf - "$out"
break # We only want this to run once
done
done