我已经编写了我的第一个 bash 脚本。我的目标是让我的办公室“无纸化”。我有很多扫描的文档,我想用日期(通常位于每个文档的顶部)作为文件名前缀来保存它们。脚本应该执行以下操作:
- 在 pdf 上进行 ocr
- 在前 100 行中查找日期。日期采用德语格式,属于以下模式之一(这也是优先顺序):a) 01.02.2020 b) 01. Februar 2020 c) 01. Feb. 2020
- 如果找到日期,则将其转换为以下格式的字符串:2020-02-01-,并将原始文件名重命名为生成的日期模式 2020-02-01-file-##.pdf(否则保留原始文件名)
这是我到目前为止的 bash 脚本。它能工作,但并不完美。我的测试(到目前为止)表明它找不到列出的格式 b) 或 c) 中的日期。
#!/bin/bash
shopt -s extglob
$datum
$twistdatum
$counter
FILES="$(find -name "*.pdf")"
for f in $FILES
do
ocrmypdf $f $f -l deu --rotate-pages --clean --rotate-pages-threshold 5
less $f | head -100 > "tmp.txt" # read the first 100 lines and safe it to a temporary text file
libreoffice --convert-to "pdf" "tmp.txt" # convert the temporary text file to pdf so that it can be processed with pdfgrep
# pdfgrep to get the 3 listed types of dates by using 3 regular expressions
datum="$(pdfgrep -o -m 1 --regexp="((0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[0-2])\.([2][0-9]{3}))|((0[1-9]|[12][0-9]|3[01])\. (Januar|Februar|März|April|Mai|Juni|Juli|August|Oktober|November|Dezember) ([2][0-9]{3}))|((0[1-9]|[12][0-9]|3[01])\. (Jan|Feb|Mär|Apr|Mai|Jun|Jul|Aug|Okt|Nov|Dez)\. ([2][0-9]{3}))" tmp.pdf)"
case "$datum" in # the three cases a) b) and c) for the different conversions are listed here
+([0][1-9]|[12][0-9]|[3][01]).+([0][1-9]|[1][0-2]).[2][0][0-4][0-9]) # this is case a); it works
twistdatum="${datum:${#datum}-4:4}-${datum:${#datum}-7:2}-${datum:0:2}-filename.pdf"
mv $f $twistdatum;;
+([0][1-9]|[12][0-9]|[3][01])@(.)@( )+(Januar|Februar|M\u00e4rz|April|Mai|Juni|Juli|August|Oktober|November|Dezember)@( )[2][0][0-4][0-9]) # this is case b) which doesn't work
firstspace="$(expr index "$datum" " ")"
case "$datum" in # this is for the conversion of the German words to English
Januar) datum="${datum/"Januar"/"January"}";;
Februar) datum="${datum/"Februar"/"February"}";;
# the other translations of the German months would be listed here
esac
langdatum="${datum:0:2} ${datum:$firstspace:3} ${datum:${#datum}-4:4}"
twistdatum="$(date -d "$langdatum" +"%F")-filename.pdf"
mv $f $twistdatum;;
+([0][1-9]|[12][0-9]|[3][01])@(.)@( )+(Jan|Feb|M\u00e4r|Apr|Mai|Jun|Jul|Aug|Okt|Nov|Dez)@(.)@( )[2][0][0-4][0-9]) # this is case c) which doesn't work
firstspace="$(expr index "$datum" " ")"
case "$datum" in # this is for the conversion of the abbreviations of the German words to English
Mär) datum="${datum/"Mär"/"Mar"}";;
Mai) datum="${datum/"Mai"/"May"}";;
# the other translations of the German months would be listed here
esac
langdatum="${datum:0:2} ${datum:$firstspace:3} ${datum:${#datum}-4:4}"
twistdatum="$(date -d "$langdatum" +"%F")-filename.pdf"
mv $f $twistdatum;;
esac
done
我认为原因可能是我在 case 块中的模式匹配不太正确。我不得不承认,我并不完全理解 bash 中的模式匹配。正则表达式对我来说更直观。:P 任何帮助和代码优化都将不胜感激。
感谢你们!
答案1
@meuh:非常感谢您的详细回答。这很有帮助。而且您的案例陈述非常简洁,真是太棒了。我刚刚意识到我的子案例陈述不正确。
case "$datum"
Januar) datum="${datum/"Januar"/"January"}";;
当然应该是:
case "$datum"
*Januar*) datum="${datum/"Januar"/"January"}";;
只是缺少了星号。无论如何,如果没有你的帮助,我无法找到这个错误。代码现在运行完美。谢谢。这个“案子”现在结案了。:)
答案2
仅使用正则表达式和案例模式编写脚本:
shopt -s extglob
f(){
echo "$1" |
egrep -o -m 1 "((0[1-9]|[12][0-9]|3[01])\.(0[1-9]|1[0-2])\.([2][0-9]{3}))|((0[1-9]|[12][0-9]|3[01])\. (Januar|Februar|März|April|Mai|Juni|Juli|August|Oktober|November|Dezember) ([2][0-9]{3}))|((0[1-9]|[12][0-9]|3[01])\. (Jan|Feb|Mär|Apr|Mai|Jun|Jul|Aug|Okt|Nov|Dez)\. ([2][0-9]{3}))"
case "$1" in
+([0][1-9]|[12][0-9]|[3][01]).+([0][1-9]|[1][0-2]).[2][0][0-4][0-9])
echo a;;
+([0][1-9]|[12][0-9]|[3][01])@(.)@( )+(Januar|Februar|M\u00e4rz|April|Mai|Juni|Juli|August|Oktober|November|Dezember)@( )[2][0][0-4][0-9])
echo b;;
+([0][1-9]|[12][0-9]|[3][01])@(.)@( )+(Jan|Feb|M\u00e4r|Apr|Mai|Jun|Jul|Aug|Okt|Nov|Dez)@(.)@( )[2][0][0-4][0-9])
echo c;;
*) echo fail;;
esac
}
egrep
表明它们在以下匹配正则表达式和case
a、b 或 c 的测试中正常工作:
f 01.02.2020
f '01. Februar 2020'
f '01. Feb. 2020'
然而这些并不匹配:
f '01. März 2020'
f '01. Mär. 2020'
您应该发现,如果将 unicode 序列括起来,它将会起作用$'...'
,例如M$'\u00e4'rz
。
当然,由于您已经使用正则表达式匹配过,因此您知道数据只能有三种形式之一,因此提供如此详细的案例模式只是在重复工作。您不妨直接使用:
case "$1" in
*.??.*) echo A ;;
*.*.*) echo C ;;
*) echo B ;;
esac