我需要在Linux / Solaris机器中重命名很多目录和文件。 有许多链接指向那些目录/文件。
首先,我创建以下脚本,以便找到我想要重命名的所有目录(例如DOMAIN.city.country
,DOMAIN.type.country
等。)
和他们的联系。
该脚本从文件info.file
文件中获取节点的旧名称和新名称。每行中的第一个字段表示旧目录名称,第二个字段表示新目录名称。
档案find_and_recreate_link_to_new_dir.ksh
while read -r line ; do
[[ -z $line ]] && continue
name_old_dir=` echo $line | awk '{print $1}' `
name_new_dir=` echo $line | awk '{print $2}' `
find / -type l -exec ls -l 2>/dev/null '{}' \; | perl -ne'BEGIN { $str = shift(@ARGV); } print if /\Q$str\E/; ' $name_old_dir
done < /tmp/test/info.file
档案/tmp/test/info.file
DOMAIN.city.country DOMAIN.world.country
DOMAIN.city1.country DOMAIN.world1.country
...
当我运行我的脚本时,我得到了这个输出
lrwxrwxrwx 1 root root 19 Mar 15 11:22 /var/test/info.domain2.com -> DOMAIN.city.country
lrwxrwxrwx 1 root root 19 Mar 15 11:22 /var/test/info.domain.com -> DOMAIN.city.country
lrwxrwxrwx 1 root root 19 Mar 15 11:22 /var/test/info.domain1.com -> DOMAIN.city.country
lrwxrwxrwx 1 root root 5 Mar 15 11:57 /var/test/DOMAIN.type.country -> mkdir
lrwxrwxrwx 1 root root 19 Mar 15 11:58 /var/test/info.tyep.com -> DOMAIN.type.country
...
现在我需要在此脚本中添加一个部分,该部分将重新创建指向新目录的当前链接。例如
/var/test/info.domain2.com -> DOMAIN.world.country
请告知最佳解决方案,以自动重新创建指向新目录的当前链接。
答案 0 :(得分:1)
如果我正确理解了问题,您希望根据来自find_and_recreate_link_to_new_dir.ksh
的信息创建符号链接。
所以,如果你得到
lrwxrwxrwx 1 root root 19 Mar 15 11:22 /var/test/info.domain2.com -> DOMAIN.city.country
您需要创建链接
/var/test/info.domain2.com -> DOMAIN.city.country
在这种情况下,我建议您存储这两个参数并使用它们调用ln -s
。将数据保存在文件中会很有意思,让我们说FILE_WITH_NEW_DATA:
find / -type l -exec ls -l 2>/dev/null '{}' \; | perl -ne'BEGIN { $str = shift(@ARGV); } print if /\Q$str\E/; ' $name_old_dir >> FILE_WITH_NEW_DATA
然后,给出字符串
lrwxrwxrwx 1 root root 19 Mar 15 11:22 /var/test/info.domain2.com -> DOMAIN.city.country
您可以通过以下方式获取参数:
link = $(awk 'N=NF-2 {print $N}')
file = $(awk '{print $NF}')
然后使用ln -s $file $link
创建符号链接。
一起,
...
find / -type l -exec ls -l 2>/dev/null '{}' \; | perl -ne'BEGIN { $str = shift(@ARGV); } print if /\Q$str\E/; ' $name_old_dir >> FILE_WITH_DATA
...
while read -r line ; do
[[ -z $line ]] && continue
link = $(echo $line | awk 'N=NF-2 {print $N}')
file = $(echo $line | awk '{print $NF}')
# begin OPTION 1) we delete previous link
rm $link
ln -s $file $link
# end OPTION 1)
# begin OPTION 2) we force the link to be created and replace the older one
ln -s -f $file $link
# end OPTION 2)
done < FILE_WITH_NEW_DATA
答案 1 :(得分:0)
您的脚本效率不高。对于要映射的每个文件,它运行awk
两次(与后面的内容相比,这是次要的peccadillo),然后在整个机器上运行find
寻找符号链接,并运行ls
对于每个符号链接,仅选择显示旧名称的链接。
遍历整个文件系统的速度极慢;你只能负担一次。
我认为您应该使用更复杂的Perl脚本(因为您已经在使用Perl)来完成大部分工作,但您可以保留find
命令,尽管也可以使用Perl的文件::查找(核心)模块。
Perl脚本将被赋予映射文件(/tmp/test/info.file
)作为参数,以及来自find
命令的符号链接:
同时在哈希中记录旧名称和新名称以进行映射
阅读符号链接名称的标准输入
shell脚本变为:
find / -type l -print | perl rebuild.links.pl /tmp/test/info.file
Perl脚本变为(警告 - 未经测试的代码):
#!/usr/bin/env perl
use strict;
use warnings;
my %map;
die "Usage: $0 map-file\n" unless @ARGV == 1;
{
open my $fh, '<', $ARGV[0] or die "Unable to open $ARGV[0] for reading\n";
while (<$fh>)
{
chomp;
next if m/^\s*$/; # Skip blank lines
next if m/^#/; # Skip comment lines
my($old, $new) = split /\s+/, $_;
if (-f $old)
{
$map{$old} = $new;
rename $old, $new or die "Failed to rename $old to $new\n";
}
}
close $fh;
}
shift @ARGV; # Lose the file name
# Read standard input for symlink names
while (my $source = <>)
{
chomp $source;
my $oldlink = readlink $_;
MAP:
for my $old (keys %map)
{
if ($oldlink =~ m%$old%)
{
my $target = $oldlink;
$target =~ s%$old%$map{$old}%;
die "Mapped name $target does not exist for symlink $source (old link $oldlink)\n"
unless -e $target;
unlink $source or die "Failed to remove symlink $source\n";
symlink $target, $source or die "Failed to create symlink $source for $target\n";
last MAP;
}
}
}
显示的代码编译(perl -c
)但尚未运行。将其视为我认为您的代码应该是什么样子的改进大纲。在您考虑测试之前应该确保理解的问题包括:
/tmp/test/info.file
中的名称是否正确?它们是绝对名称,还是相对于当前目录的简单名称?为了调试代码,我可能会:
use constant debug => 1;
。unlink
打印而不是执行symlink
,rename
,if debug;
等。find
上运行/
命令,直到我确定我知道发生了什么为止。小心 - 这是危险的东西。