在 bash 中使用模式匹配来处理 case 语句(而不是正则表达式)

在 bash 中使用模式匹配来处理 case 语句(而不是正则表达式)

我已经编写了我的第一个 bash 脚本。我的目标是让我的办公室“无纸化”。我有很多扫描的文档,我想用日期(通常位于每个文档的顶部)作为文件名前缀来保存它们。脚本应该执行以下操作:

  1. 在 pdf 上进行 ocr
  2. 在前 100 行中查找日期。日期采用德语格式,属于以下模式之一(这也是优先顺序):a) 01.02.2020 b) 01. Februar 2020 c) 01. Feb. 2020
  3. 如果找到日期,则将其转换为以下格式的字符串: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表明它们在以下匹配正则表达式和casea、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

相关内容