如何将 xargs 与 pdftotext 转换器耦合以在多个 pdf 文件中搜索
how to couple xargs with pdftotext converter to search inside multiple pdf files
我正在制作一个脚本,该脚本应该在目录中的所有 pdf 文件中进行搜索。我找到了一个名为 "pdftotext" 的转换文件,它使我能够在 pef 文件上使用 grep,但我只能对一个文件进行 运行。当我想 运行 它遍历目录中存在的所有文件时,它就会失败。有什么建议么 ?
这个works:for一个文件
pdftotext my_file.pdf - | grep 'hot'
这失败了:用于搜索 pdf 文件并转换为文本和 greping
SHELL PROMPT>find ~/.personal/tips -type f -iname "*" | grep -i "*.pdf" | xargs pdftotext |grep admin
pdftotext version 3.00
Copyright 1996-2004 Glyph & Cog, LLC
Usage: pdftotext [options] <PDF-file> [<text-file>]
-f <int> : first page to convert
-l <int> : last page to convert
-layout : maintain original physical layout
-raw : keep strings in content stream order
-htmlmeta : generate a simple HTML file, including the meta information
-enc <string> : output text encoding name
-eol <string> : output end-of-line convention (unix, dos, or mac)
-nopgbrk : don't insert page breaks between pages
-opw <string> : owner password (for encrypted files)
-upw <string> : user password (for encrypted files)
-q : don't print any messages or errors
-cfg <string> : configuration file to use in place of .xpdfrc
-v : print copyright and version info
-h : print usage information
-help : print usage information
--help : print usage information
-? : print usage information
SHELL PROMPT 139>
xargs
是这项工作的错误工具:find
内置了您需要的一切。
find ~/.personal/tips \
-type f \
-iname "*.pdf" \
-exec pdftotext '{}' - ';' \
| grep hot
就是说,如果您 确实 出于某种原因想要使用 xargs
,正确的用法应该类似于...
find ~/.personal/tips \
-type f \
-iname "*.pdf" \
-print0 \
| xargs -0 -J % -n 1 pdftotext % - \
| grep hot
注意:
find
命令使用 -print0
对其输出进行 NUL 分隔
xargs
命令使用 -0
对其输入进行 NUL 分隔(这也关闭了一些行为,这些行为会导致不正确处理名称中包含空格、文字引号字符等的文件名).
xargs
命令使用-n 1
为每个文件调用一次pdftotext
xargs
命令使用 -J %
指定替换应该发生的地方的印记,并在 pdftotext 命令行中适当地使用 %
。
find . -name '*.pdf' -print0 | xargs -0 -n1 -I '{}' pdftotext '{}' -
默认情况下,xargs 将尝试在 pdftotext 的命令行上放置尽可能多的行。你不想要那个。
您想要的是每次调用一个文件,后跟“-”。这可以通过 -n1
(每次调用限制为一个参数)和 -I '{}'
(使 {} 成为参数适合的占位符)来实现。
find 的 -print0
选项与 xargs 的 -0
选项相结合,使得两者都使用 '\0'(空字节)而不是换行符('\n')作为参数分隔符。
Xargs 与 -n1
和 -I{}
这样使用在语义上几乎等同于 Charles Duffy 推荐的 find -exec
。 Xargs 具有可以利用多核处理器的优势(它可以 运行 一次 pdftotext 的多个实例;您可以使用 -P
开关配置数量)。
通过正则表达式连接每个 pdf 中找到的所有代码并使用找到的代码重命名每个 pdf 文件名的答案。
要在PDF文件中搜索的shell正则表达式对应的代码示例
- File1.pdf:X123456
- File1.pdf:A1234567
- File2.pdf:X003456
- File2.pdf:A0034567
因此 File1 和 File2 文件将被重命名:
- X123456_A1234567_File1.pdf
- X003456_A0034567_File2.pdf
文件名批次find_codes_in_pdf_and_rename.sh
待执行
chmod +x find_codes_in_pdf_and_rename.sh
执行并输出到屏幕和日志(sed
在 Windows 下使用 CR+LF 可读)。
./find_codes_in_pdf_and_rename.sh 2>&1 | tee | sed -u 's/$/\r/' 2>&1 | tee find_codes_in_pdf_and_rename.sh_$(date "+%Y_%m_%d_%Hh_%M_%S").log
#!/bin/bash -e
PrevFile=""
PrevCodes=""
mycmd1=""
mycmd2=""
DIRPrevFile="."
DIRFile="."
BASEFile=""
# look for files where the extension is pdf
# -print0 to have character zero to manage file name with space
find /my_path/ -iname "*.pdf" -print0 |
# head for debug only two files, -z for print0
# # head -z -n 2 |
# sort, -z for print0
sort -z|
# exclude filename with code yet in filename, -z for print0
grep -z -v -E ".*[\s\.\/][A-Z][0-9]{6,7}.*" |
# list filename:code
xargs -0 pdfgrep -i --only-matching --with-filename -e "([A-Z]{1}[0-9]{6,7})" 2>&1 |
# exclude "pdfgrep: Could not open"
tee| grep -v "pdfgrep: Could not open" |
# exclude empty lines
grep -v -e '^$' |
# find path of filename in regexp code group 1
# and code in regexp code group 3
# and keep only that in the list with the character ':' at the middle.
# It's partially redundant if pdfgrep works well with --only-matching
sed --regexp-extended -e 's/(.):(.*)([A-Z][0-9]{6,7})(.*)/:/gm' |
uniq| {
while read line
do
File=$( echo "$line" |cut -d\: -f1 )
code=$( echo "$line" |cut -d\: -f2 )
#echo File $File
#echo code $code
if [ "$PrevFile" == "" ]
then
PrevFile=$File
fi
if [ "$PrevFile" == "$File" ] && [ -n "$PrevCodes" ]
then
# concatenate all previous code to current code for the same filename
PrevCodes="${PrevCodes} ${code}"
else
PrevCodes=$code
fi
# uniques codes
PrevCodes=$(echo $PrevCodes | tr ' ' '\n' | sort | uniq | tr '\n' ' ')
# echo $PrevCodes
DIRPrevFile=`dirname "${PrevFile}"`
DIRFile=`dirname "${File}"`
#echo $DIRPrevFile
if [ "${DIRPrevFile}/${PrevFile}" != "${DIRFile}/${File}" ]
then
# computed at the previous loop of filename
# echo "MVFake ${mycmd1}" "${mycmd2}"
set -x
mv "${mycmd1}" "${mycmd2}"
set +x
fi
# to remove old PDF extension
BASEFile=$(echo `basename "${File}" .pdf` )
# mycmd1: old filename
mycmd1="$File"
# concatenate all codes with the old filename, and replace . and space with _
target=$(echo "${PrevCodes} ${BASEFile}" | sed "s/[ .]/_/g" )
mycmd2=$(echo "${DIRPrevFile}/${target}.pdf" )
PrevFile=$File
done
# echo "MVFake ${mycmd1}" "${mycmd2}"
set -x
mv "${mycmd1}" "${mycmd2}"
set +x
}
这是一个 Linux 问题,因此主要是如何使用命令行在 Linux 中搜索所有 pdf 文件以查找“hot”。
对于 windows 用户,您需要使用 for 或 forfiles 稍微不同的语法来递归目录,例如:-
forfiles /P "C:\Users\WDAGUtilityAccount\Desktop\SandBox" /S /M *.pdf /C "cmd /c pdftotext @file - |find /I \" hot \"
然而,这会产生大量混合输出,包括许多 pdf 错误与有效输出混合在一起,例如
Syntax Warning: Invalid Font Weight
Syntax Warning: Invalid Font Weight
identifies hot (frequently executed) bytecode sequences, records
their time in hot loops. Even in dynamically typed languages, we
....
.....
但是有一个更简单的方法,那就是(首先确保你安装了 pdf iFilter)只需在文件搜索中添加“hot”,所以我们在这里找到了所有沙盒文件夹中有 26 个结果。
我正在制作一个脚本,该脚本应该在目录中的所有 pdf 文件中进行搜索。我找到了一个名为 "pdftotext" 的转换文件,它使我能够在 pef 文件上使用 grep,但我只能对一个文件进行 运行。当我想 运行 它遍历目录中存在的所有文件时,它就会失败。有什么建议么 ?
这个works:for一个文件
pdftotext my_file.pdf - | grep 'hot'
这失败了:用于搜索 pdf 文件并转换为文本和 greping
SHELL PROMPT>find ~/.personal/tips -type f -iname "*" | grep -i "*.pdf" | xargs pdftotext |grep admin
pdftotext version 3.00
Copyright 1996-2004 Glyph & Cog, LLC
Usage: pdftotext [options] <PDF-file> [<text-file>]
-f <int> : first page to convert
-l <int> : last page to convert
-layout : maintain original physical layout
-raw : keep strings in content stream order
-htmlmeta : generate a simple HTML file, including the meta information
-enc <string> : output text encoding name
-eol <string> : output end-of-line convention (unix, dos, or mac)
-nopgbrk : don't insert page breaks between pages
-opw <string> : owner password (for encrypted files)
-upw <string> : user password (for encrypted files)
-q : don't print any messages or errors
-cfg <string> : configuration file to use in place of .xpdfrc
-v : print copyright and version info
-h : print usage information
-help : print usage information
--help : print usage information
-? : print usage information
SHELL PROMPT 139>
xargs
是这项工作的错误工具:find
内置了您需要的一切。
find ~/.personal/tips \
-type f \
-iname "*.pdf" \
-exec pdftotext '{}' - ';' \
| grep hot
就是说,如果您 确实 出于某种原因想要使用 xargs
,正确的用法应该类似于...
find ~/.personal/tips \
-type f \
-iname "*.pdf" \
-print0 \
| xargs -0 -J % -n 1 pdftotext % - \
| grep hot
注意:
find
命令使用-print0
对其输出进行 NUL 分隔xargs
命令使用-0
对其输入进行 NUL 分隔(这也关闭了一些行为,这些行为会导致不正确处理名称中包含空格、文字引号字符等的文件名).xargs
命令使用-n 1
为每个文件调用一次pdftotext
xargs
命令使用-J %
指定替换应该发生的地方的印记,并在 pdftotext 命令行中适当地使用%
。
find . -name '*.pdf' -print0 | xargs -0 -n1 -I '{}' pdftotext '{}' -
默认情况下,xargs 将尝试在 pdftotext 的命令行上放置尽可能多的行。你不想要那个。
您想要的是每次调用一个文件,后跟“-”。这可以通过 -n1
(每次调用限制为一个参数)和 -I '{}'
(使 {} 成为参数适合的占位符)来实现。
find 的 -print0
选项与 xargs 的 -0
选项相结合,使得两者都使用 '\0'(空字节)而不是换行符('\n')作为参数分隔符。
Xargs 与 -n1
和 -I{}
这样使用在语义上几乎等同于 Charles Duffy 推荐的 find -exec
。 Xargs 具有可以利用多核处理器的优势(它可以 运行 一次 pdftotext 的多个实例;您可以使用 -P
开关配置数量)。
通过正则表达式连接每个 pdf 中找到的所有代码并使用找到的代码重命名每个 pdf 文件名的答案。
要在PDF文件中搜索的shell正则表达式对应的代码示例
- File1.pdf:X123456
- File1.pdf:A1234567
- File2.pdf:X003456
- File2.pdf:A0034567
因此 File1 和 File2 文件将被重命名:
- X123456_A1234567_File1.pdf
- X003456_A0034567_File2.pdf
文件名批次find_codes_in_pdf_and_rename.sh
待执行
chmod +x find_codes_in_pdf_and_rename.sh
执行并输出到屏幕和日志(sed
在 Windows 下使用 CR+LF 可读)。
./find_codes_in_pdf_and_rename.sh 2>&1 | tee | sed -u 's/$/\r/' 2>&1 | tee find_codes_in_pdf_and_rename.sh_$(date "+%Y_%m_%d_%Hh_%M_%S").log
#!/bin/bash -e
PrevFile=""
PrevCodes=""
mycmd1=""
mycmd2=""
DIRPrevFile="."
DIRFile="."
BASEFile=""
# look for files where the extension is pdf
# -print0 to have character zero to manage file name with space
find /my_path/ -iname "*.pdf" -print0 |
# head for debug only two files, -z for print0
# # head -z -n 2 |
# sort, -z for print0
sort -z|
# exclude filename with code yet in filename, -z for print0
grep -z -v -E ".*[\s\.\/][A-Z][0-9]{6,7}.*" |
# list filename:code
xargs -0 pdfgrep -i --only-matching --with-filename -e "([A-Z]{1}[0-9]{6,7})" 2>&1 |
# exclude "pdfgrep: Could not open"
tee| grep -v "pdfgrep: Could not open" |
# exclude empty lines
grep -v -e '^$' |
# find path of filename in regexp code group 1
# and code in regexp code group 3
# and keep only that in the list with the character ':' at the middle.
# It's partially redundant if pdfgrep works well with --only-matching
sed --regexp-extended -e 's/(.):(.*)([A-Z][0-9]{6,7})(.*)/:/gm' |
uniq| {
while read line
do
File=$( echo "$line" |cut -d\: -f1 )
code=$( echo "$line" |cut -d\: -f2 )
#echo File $File
#echo code $code
if [ "$PrevFile" == "" ]
then
PrevFile=$File
fi
if [ "$PrevFile" == "$File" ] && [ -n "$PrevCodes" ]
then
# concatenate all previous code to current code for the same filename
PrevCodes="${PrevCodes} ${code}"
else
PrevCodes=$code
fi
# uniques codes
PrevCodes=$(echo $PrevCodes | tr ' ' '\n' | sort | uniq | tr '\n' ' ')
# echo $PrevCodes
DIRPrevFile=`dirname "${PrevFile}"`
DIRFile=`dirname "${File}"`
#echo $DIRPrevFile
if [ "${DIRPrevFile}/${PrevFile}" != "${DIRFile}/${File}" ]
then
# computed at the previous loop of filename
# echo "MVFake ${mycmd1}" "${mycmd2}"
set -x
mv "${mycmd1}" "${mycmd2}"
set +x
fi
# to remove old PDF extension
BASEFile=$(echo `basename "${File}" .pdf` )
# mycmd1: old filename
mycmd1="$File"
# concatenate all codes with the old filename, and replace . and space with _
target=$(echo "${PrevCodes} ${BASEFile}" | sed "s/[ .]/_/g" )
mycmd2=$(echo "${DIRPrevFile}/${target}.pdf" )
PrevFile=$File
done
# echo "MVFake ${mycmd1}" "${mycmd2}"
set -x
mv "${mycmd1}" "${mycmd2}"
set +x
}
这是一个 Linux 问题,因此主要是如何使用命令行在 Linux 中搜索所有 pdf 文件以查找“hot”。
对于 windows 用户,您需要使用 for 或 forfiles 稍微不同的语法来递归目录,例如:-
forfiles /P "C:\Users\WDAGUtilityAccount\Desktop\SandBox" /S /M *.pdf /C "cmd /c pdftotext @file - |find /I \" hot \"
然而,这会产生大量混合输出,包括许多 pdf 错误与有效输出混合在一起,例如
Syntax Warning: Invalid Font Weight
Syntax Warning: Invalid Font Weight
identifies hot (frequently executed) bytecode sequences, records
their time in hot loops. Even in dynamically typed languages, we
....
.....
但是有一个更简单的方法,那就是(首先确保你安装了 pdf iFilter)只需在文件搜索中添加“hot”,所以我们在这里找到了所有沙盒文件夹中有 26 个结果。