在 Unix shell 脚本中根据文件第一行中的匹配字符串重命名文本文件

在 Unix shell 脚本中根据文件第一行中的匹配字符串重命名文本文件

我是 Unix 脚本编写新手。

我想根据第一行中的匹配字符串(即以 开头的行HDR)重命名文件。

我有一个文本文件 ( File.txt),如下所示:

HDR##############################1234###
########################################
########################################

下面是我的代码。如何在代码中更具体地检查文件中以模式 or 开头HDR并具有模式1234or的第一行5678

if grep -o "1234" File.txt

then mv File.txt Pattern1.txt

echo "File with pattern1 received..."

elif grep -o "5678" File.txt

then mv File.txt Pattern2.txt

echo "File with pattern2 received..."

else

echo "File have no matching pattern..."

fi

答案1

使用“read”读取一行,然后使用“case”决定要做什么。

{
  IFS= read -r Firstline
  case "$Firstline" in
     ("HDR"*"1234"*) mv File.txt Pattern1.txt
                echo "File with pattern1 received..." ;;
     ("HDR"*"5678"*) mv File.txt Pattern2.txt
                echo "File with pattern2 received..." ;;
     (*)        echo "Nothing matched" ;;
  esac
} < File.txt

答案2

使用-n( --line-number) 选项grep确定行,然后case匹配模式:

Tmp=$(grep -n "HDR.*[0-9]\{4\}" File.txt)
if [ "${Tmp%:*}" -eq 1 ]
  then  case "${Tmp#*:}" in
          HDR*1234*)    NewName="Pattern1";;
          HDR*5678*)    NewName="Pattern2";;
        esac
        if [ "$NewName" ]
          then  mv -- File.txt "$NewName".txt
                echo "File with $NewName received..."
          else  echo "File doesn't have a matching pattern..."
        fi
  else  echo "File doesn't have a pattern in line 1"
fi

答案3

使用 perlrename实用程序。

注意:perl rename 也称为file-renameperl-rename、 或prename。不要将其与具有完全不同且不兼容的功能和命令行选项的rename实用程序混淆。util-linux

$ rename -n ' BEGIN {
      # This block runs only once when the script starts, there's no need
      # to redefine these vars on every pass through the loop.  File::Rename
      # scripts run with `use strict vars`, so we need to be careful about
      # variable scope.  See `perldoc -f our`
      our %patterns=(1234 => "Pattern1.txt", 5678 => "Pattern2.txt");
      our $re = "^HDR#+(" . join("|",keys %patterns) . ")#+$";
    };
    
    # The remainder of the script runs once for every filename
    our (%patterns, $re); # these vars are in File::Rename lexical scope

    open(my $fh,"<",$_); my $line=<$fh>; close($fh);
    if ($line =~ /$re/) { $_ = $patterns{$1} }' File*
rename(File1.txt, Pattern1.txt)
rename(File2.txt, Pattern2.txt)

(这是在两个文本文件(示例数据的副本)上运行的。File1.txt 包含与 File.txt 示例完全相同的 1234,而 File2.txt 已编辑为包含 5678)。

-n选项使其成为一次试运行,因此它只会显示它将执行的操作,而不会实际重命名任何文件。当您确认它符合您的要求后,请删除-n,或将其替换为 以获得详细输出。-v

此重命名脚本使用哈希%patterns来保存要搜索的模式以及要重命名包含该模式的文件的文件名。它根据变量中的哈希键构造正则表达式$re

然后它打开当前文件名,并读取第一行。如果第一行与其中一个模式匹配,则会将其重命名为相应的文件名。

使用这样的哈希可以让脚本轻松地使用更多或不同的模式进行扩展。除了%patterns散列(以及中的^HDR#+(和)之外,没有任何内容是硬编码的。)#+$$re

注意:重命名不会覆盖现有文件,除非您使用-f--force选项强制重命名。这适用于现有文件和刚刚重命名的文件 - 如果多个文件包含相同的模式,则只有第一个文件会被重命名。-f当然,使用将覆盖任何现有/以前重命名的文件 - 更好的替代方案是使用计数器变量(例如以文件名或模式作为键的散列)将文件重命名为,例如Pattern1.txt.001,,Pattern1.txt.002等。

或者借助以下fileparse()功能文件::基本名称模块到Pattern1-001.txt,Pattern1-002.txt

例如

$ rename -n 'BEGIN {
    use File::Basename;
    our %seen=();
    our %patterns=(1234 => "Pattern1.txt", 5678 => "Pattern2.txt");
    our $re = "^HDR#*(" . join("|",keys %patterns) . ")"
  };

  our(%seen, %patterns, $re);
  open(my $fh,"<",$_); my $line=<$fh>; close($fh);
  if ($line =~ /$re/) {
    my($name,$path,$suffix) = fileparse($patterns{$1}, qr/\.[^.]*$/);
    $_ = sprintf "%s-%03i%s", $name, ++$seen{$1}, $suffix
  }' File*
rename(File1.txt, Pattern1-001.txt)
rename(File2.txt, Pattern2-001.txt)
rename(File3.txt, Pattern1-002.txt)

相关内容