1

Linux/Solarisマシンの多くのディレクトリとファイルの名前を変更する必要があります。それらのディレクトリ/ファイルを指す多くのリンクがあります。

DOMAIN.city.countryしたがって、最初に、 名前を変更するすべてのディレクトリ(DOMAIN.type.countryなど)とそれらのリンクを見つけるために、次のスクリプトを作成します。

スクリプトは、ファイルファイルからノードの新旧の名前を取得しinfo.fileます。各行の最初のフィールドは古いディレクトリ名を表し、2番目のフィールドは新しいディレクトリ名を表します。

ファイル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

新しいディレクトリへの現在のリンクを自動的に再作成するための最良の解決策をアドバイスしてください。

4

2 に答える 2

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
于 2013-03-15T12:38:09.030 に答える
0

スクリプトはあまり効率的ではありません。マップするファイルごとに、awk2回実行され(以下と比較するとマイナーなペッカディロです)、findマシン全体でシンボリックリンクを探して実行され、lsシンボリックリンクごとに実行され、古い名前が表示されているリンクのみが選択されます。

ファイルシステム全体をトラバースするのは非常に遅いです。あなたは一度だけそれをする余裕があります。

ほとんどの作業を行うには、より複雑なPerlスクリプトを使用する必要があると思います(すでにPerlを使用しているため)が、findPerlのFile :: Find(コア)モジュールを使用することも可能ですが、コマンドを保持できます。

Perlスクリプトには、引数としてマッピングファイル()が与えられ、コマンド/tmp/test/info.fileからのシンボリックリンクが与えられます。find

  • ファイルから行を読み取ります
  • それに応じてファイルの名前を変更します
  • また、マッピングのために古い名前と新しい名前をハッシュに記録します

  • シンボリックリンク名の標準入力を読み取る

  • シンボリックリンクのターゲットを読み取るには、readlinkを使用します
  • リンクが古い名前のいずれかと一致する場合
    • 古いリンクを削除します
    • 新しいリンクを作成します

シェルスクリプトは次のようになります。

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、、、などsymlinkrename条件を実行する代わりに印刷しますif debug;
  • 何が起こっているのかがわかるまでではfindなく、サブディレクトリに対してコマンドを実行します。/

注意してください—これは危険なことです。

于 2013-03-15T13:06:17.480 に答える