Bash,在文件名中搜索模式并进行比较

Bash,在文件名中搜索模式并进行比较

我正在尝试通过 Bash 脚本根据模式移动文件。

我使用 find 来选择我的所有摄像机文件并将结果保存到 TXT 文件中。

我的每个摄像机文件都包含年份位置,我想使用 Grep 或其他东西来查找此字符串(4 位数字的年份,即 1984)并比较此字符串以将文件移动到不同的文件夹中,如果文件在 1984 年之后,那么我的文件必须进入文件夹“Marie”,如果文件在 1984 年之前或等同于 1984 年,则必须进入文件夹“Marie_Liam”。

我尝试了几种方法,使用 Grep 并在 read -r line 时进行尝试,但是当我比较找到的字符串(年份)时,我的脚本每次都会返回 1984 年之后的内容...

这是我的不同尝试:

我已经尝试了几件类似的事情(需要很多次尝试,而不仅仅是一个脚本):

基本脚本:

#!/bin/bash
find /home/CamFiles/ -name "*.m2ts"

尝试1:

TestScriptResultFile="/home/Dio/CamCorderFindResult.file"
do
  if [ grep -e " 1984 " "$in" ];
  then
    echo "Voici un film qui est avant 1984 $FindMovie"
  else
    echo "Voici un film qui est de 1984 : $FindMovie"
  fi;
done

-- 再试一次 --

while IFS= read -r line; do
  if [[ /bin/grep -E "[1][9][8][4]" "$MyLine" != 0 ]] ;
  then
    echo "Ok"
  fi
done < "$TestScriptResultFile"
while read line; do
  if  echo "$line" | grep -q "[1][9][8][4]"; then echo "$line"; fi
  Found=$(echo "$line" | grep -q "[1][9][0-8][0-4]")
  if [[ " $Found " <= 1984 ]]; then echo "$line"; fi
done < "$TestScriptResultFile"
exit 0

-- 再试一次 --

while read MyLine
do
  if grep -E "$MyPattern" "$MyLine"
  then
    echo "tourne apres 1984 : $MyLine"
  else
    echo "Tourne avant 1984 : $MyLine"
  fi
done < "$TestScriptResultFile"

感谢您的帮助。

此致。

答案1

我根据您在评论中提供的文件名示例更新了脚本:

"Liam sur la moto (VHS) (2001) - Maison 13100.m2ts" 
"M&L Plage 1080i (2012) - Camargue 30240.m2ts

我想出了两种方法来处理这个命名约定。

第一种是假设在每种情况下年份都括在括号中。我更新了“第一个”脚本以反映这种情况;它只是对所使用的正则表达式模式的更新。

regexPat='\(\K[0-9]{4,4}(?=\))'

第二个脚本已更新,以显示不同的方法,我们无法确定年份是否用括号括起来。在这里,我们将 grep 评估的结果读出为数组,以防有多个匹配项,然后对年份进行健全性检查 - 即年份必须介于 1970 年至 2020 年之间;否则我们假设它不是年份。


请注意readarray命令(又名 mapfile)仅在 Bash 版本 4.x+ 中可用。底部是仅使用 的更便携的版本read这可能很棘手解析输出,find而不会因文件名中的空格或特殊字符而导致任何中断。

脚本 1


#!/bin/bash
# Create test files
touch abcd\({2001,1985,1984,1931}\)efgh.m2ts
touch abcd{24001,198a5,19b84,1912331,1293}.m2ts
touch "abcd 1232 adffd.m2ts"
touch "Liam sur la moto (VHS) (2001) - Maison 13100.m2ts"
touch "M&L Plage 1080i (2012) - Camargue 30240.m2ts" 
TestScriptResultFile="./CamCorderFindResult.file"
touch $TestScriptResultFile
   
regexPat='\(\K[0-9]{4,4}(?=\))'

readarray fileList <<<"$(IFS="\n" ; find . -name "*.m2ts" -exec basename {} \;)"
for i in "${fileList[@]}"; do 
  echo "Processing File: $i"
  if year=$(grep -oP "$regexPat" <<<"$i");    then
    if [ "$year" -le 1984 ]; then
      echo "1984 or earlier: $i" >> "$TestScriptResultFile"
    else
      echo "After 1984: $i" >> "$TestScriptResultFile"
    fi
  else
    echo "No valid year found in file $i"
  fi
done

1. 使用find命令获取文件列表并将其存储为数组readarray

  • 将字段分隔符设置为新行:IFS=$'\n'
  • 使用一个-exec参数,findbasename在每个文件上运行以仅获取文件名而不是路径。
  • find通过使用命令替换和一个'这里字符串'以及<<<命令readarray

2. 循环遍历文件名数组

3. 使用 grep 和 regexPat 查找嵌入的年份

  • (当第一个字符是,后面跟着 4 个数字[0-9]{4,4},最后以 结尾)时,我使用的正则表达式模式将匹配字符串中的 6 个字符。

  • 为了仅输出中间的 4 个数字(希望是年份),-P为 grep 提供了“Perl Regex”的参数,它允许将匹配的字符与捕获的(输出)字符分开,等等。

  • /K将导致 grep 不输出/K模式中与 之前匹配的任何内容(也称为展望)。

  • )最后,使用类似于的后视非捕获从输出中删除结束/K。您可以使用基本相同的语法,底部脚本显示了不使用的前视方法/K

  • -o标志告诉 grep 仅输出捕获的、匹配的字符串部分,在我们的例子中是一个 4 位数字。

脚本的其余部分根据 1984 检查该数字并进行相应的记录。


这是另一种更紧凑的方法。

这里有两件事需要注意

  • find-print0被赋予了将终止输出的参数。
  • read命令被赋予参数-d '',这告诉它它的输入是空终止的。空字符串通常\0以纯文本形式编写;在 Bash 中,您可以使用''$'\0'

脚本 2


#!/bin/bash

TestScriptResultFile="./CamCorderFindResult.file"
touch $TestScriptResultFile

regexPat='(?<=[^0-9])[0-9]{4,4}(?=[^0-9])'
find . -name "*.m2ts" -print0 | while IFS= read -r -d '' k; do
  i="$(basename "$k")"
   echo "Processing File: $i"
     if year=($(grep -oP "$regexPat" <<<"$i")); then
     for yr in "${year[@]}"; do
       if [ "$yr" -lt 1970 ] || [ "$yr" -gt 2020 ]; then
         echo "   x Out of range year ($yr) parsed from $i"
       else
         echo "   o Found year $yr"
         if [ "$yr" -le 1984 ]; then
           echo "1984 or earlier: $i" >> "$TestScriptResultFile"
         else
           echo "After 1984: $i" >> "$TestScriptResultFile"
         fi
      fi
     done
   else
     echo "   x No valid year found in file $i"
  fi
done

相关内容