![在 Unix shell 脚本中根据文件第一行中的匹配字符串重命名文本文件](https://linux22.com/image/207035/%E5%9C%A8%20Unix%20shell%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E6%A0%B9%E6%8D%AE%E6%96%87%E4%BB%B6%E7%AC%AC%E4%B8%80%E8%A1%8C%E4%B8%AD%E7%9A%84%E5%8C%B9%E9%85%8D%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6.png)
我是 Unix 脚本编写新手。
我想根据第一行中的匹配字符串(即以 开头的行HDR
)重命名文件。
我有一个文本文件 ( File.txt
),如下所示:
HDR##############################1234###
########################################
########################################
下面是我的代码。如何在代码中更具体地检查文件中以模式 or 开头HDR
并具有模式1234
or的第一行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-rename
、perl-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)