(同じディレクトリにある)他のターゲットを指すようにターゲットのすべてのシンボリックリンクを置き換えるスクリプト

(同じディレクトリにある)他のターゲットを指すようにターゲットのすべてのシンボリックリンクを置き換えるスクリプト

次のような人工的な例を見てください。

$ mkdir -p a/b && touch a/b/original-target && touch a/b/new-target
$ mkdir -p c1/c2 && cd c1/c2 && ln -s ../../a/b/original-target && cd -
$ mkdir -p d1/d2/d3 && cd d1/d2/d3 && ln -s ../../../a/b/original-target && cd -
$ tree .
.
├── a
│   └── b
│       ├── new-target
│       └── original-target
├── c1
│   └── c2
│       └── original-target -> ../../a/b/original-target
└── d1
    └── d2
        └── d3
            └── original-target -> ../../../a/b/original-target

すべてのシンボリックリンクoriginal-targetnew-target。シンボリックリンクは相対パスを使用する必要があります。

答え1

globstar私はあなたがbashを使用すると**仮定しているので。その後残ったのは少し遊んでreadlink待つことですrealpath

shopt -s globstar
for file in c1/** d1/**; do
    if [[ -h "$file" ]]; then
        if [[ "$(readlink -f "$file")" == "$(realpath a/b/original-target)" ]]; then
            ln -sf "$(dirname "$(readlink "$file")")"/new-target "$(dirname "$file")" && rm -f "$file"
        fi
    fi
done

答え2

paxできる本物このような状況に役立ちます。実際にpaxこれを行うオプションを見つけることができれば-o listopt=...簡単になります。POSIXで指定ところで、いくら見回してもこんなことができる人を見られませんでした。私は mirabilos - BSD で管理するものを使用します。pax ( mirabipax?)- 私が知っている限り、これはおそらく他のほとんどの人がやっていることです。とにかく正規表現のファイル名とファイルのリストを取得できます。たとえば、

(set -e; mkdir -p a/b c1/c2 d1/d2/d3
touch a/b/original-target a/b/new-target
cd c1/c2; ln -s ../../a/b/original-target
cd ../../d1/d2/d3; ln -s ../../../a/b/original-target)

これはあなたの木です。今それらをリストします:

pax -ws'|\(\..*/original-target.*\)*.*|\1|' ././ | 
pax -cvs'|\(.*\)/original|\1/new|p' \
     '././a/b/original-target' '*/original-target?*'

どの印刷物が...

././d1/d2/d3/original-target >> ././d1/d2/d3/new-target
lrwxrwxrwx  1 mikeserv mikeserv         0 Dec  7 18:17 ././d1/d2/d3/new-target => ../../../a/b/new-target
././c1/c2/original-target >> ././c1/c2/new-target
lrwxrwxrwx  1 mikeserv mikeserv         0 Dec  7 18:14 ././c1/c2/new-target => ../../a/b/new-target

さて、最初のアイテムはpaxアーカイブを作成します。私が提供した正規表現引数は、2番目のエントリと同じように、ストリーム内のファイル名を変更するために最も一般的に使用されていますが、1つまたは2つのトリックを使用してフィルタリングするためにも使用できます。アーカイブに追加されたファイル。ustarstdout-spax

-sこの引数を適用した後、空のファイル名がアーカイブから完全に削除されるように指定されていることがわかります。したがって、正規表現を使用してすべてのファイル名を一致させます\1-w- これはシェルのグローバル変数によって異なり、再帰的ではありません。

それにもかかわらず、書かれた正規表現はすべての文字に従うので、他方では/original-targetアーカイブをリストするときに選択項目で実装されたパターンの1つがすぐにそこに配置されるということです。完璧ではありませんが、私の言葉は、おそらくパターンを2回含むリンクがあるかもしれませんが…まあ、それはまさにそれであり、かなり良いです。追加のテストで同じ方法で処理できます。とにかく、私はそれ自体の一致も実装したので、リスト出力からも削除されました。-c*/original-target?*-c././a/b/original-file

リストモードで-eadまたはriteがpaxない場合に実行される操作。-r-wpax冗談-format-には-ls -lなどのすべてのソフトリンクターゲットが含まれますが、link => target適用可能なパラメータを適用した後にのみ可能です-s-s修飾子が次の形式で適用されるたびに、-vまったく同じパラメータが印刷されます-s|...|...|pp

"%s>>%s\n",元のパス名新しいパス名

././したがって、上記では、そうでなければ表示されないリストとリストを分離します。今仕事はとても簡単になりました。皆さんも同意してください。このタイプのデータを適用する方法については、読者が決定するようにします。lnとても簡単なはずですがあえてこれまでする必要もない

実際、その仕様は、paxユーザー、グループ、リンクデータ、ファイル名、ファイルソースなどの項目を変更するために、cliオプションを使用して読み取りまたは書き込み中にアーカイブを変更できるようにすることです。これらは非常に強力なファイル解析ツールです。しかし、私が知っている実装に最も近いのはGNUであり、部分的にのみ可能です。ヘッダーの種類に影響を与える方法が見つかりませんでした。ある程度それを行うことができますが、cliオプションを使用すると、アーカイブ自体で正規表現を使用することはあまり難しくありませんが、それは言葉です。このエントリにはヘッダフィールドがあります。rwpaxtar

...2 - シンボリックリンクを表します。シンボリックリンクの内容は、次の場所に保存する必要があります。リンク名大地。

私が本当にしたいもう一つのpaxことは-o listopt=...。以下は、仕様の例のセクションから抜粋したものです。

使用オプション:

-o listopt="%M %(atime)T %(size)D %(name)s"

...標準出力のデフォルトの出力説明を無視し、代わりに次を書き込みます。

-rw-rw--- Jan 12 15:53 2003 1492 /usr/foo/bar

使用オプション:

-o listopt='%L\t%(size)D\n%.7' \
-o listopt='(name)s\n%(atime)T\n%T'

...標準出力のデフォルトの出力説明を無視し、代わりに次を書き込みます。

/usr/foo/bar -> /tmp   1492
/usr/fo
Jan 12 15:53 1991
Jan 31 15:53 2003

だから、もしあなたがそのようなことを偶然発見したらpax…まあ、誰が見ているのか知ります。

関連情報