次のような人工的な例を見てください。
$ 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-target
をnew-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つのトリックを使用してフィルタリングするためにも使用できます。アーカイブに追加されたファイル。ustar
stdout
-s
pax
-s
この引数を適用した後、空のファイル名がアーカイブから完全に削除されるように指定されていることがわかります。したがって、正規表現を使用してすべてのファイル名を一致させます\1
。-w
- これはシェルのグローバル変数によって異なり、再帰的ではありません。
それにもかかわらず、書かれた正規表現はすべての文字に従うので、他方では/original-target
アーカイブをリストするときに選択項目で実装されたパターンの1つがすぐにそこに配置されるということです。完璧ではありませんが、私の言葉は、おそらくパターンを2回含むリンクがあるかもしれませんが…まあ、それはまさにそれであり、かなり良いです。追加のテストで同じ方法で処理できます。とにかく、私はそれ自体の一致も実装したので、リスト出力からも削除されました。-c
*/original-target?*
-c
././a/b/original-file
リストモードで-eadまたはriteがpax
ない場合に実行される操作。-r
-w
pax
冗談-format-には-ls -l
などのすべてのソフトリンクターゲットが含まれますが、link => target
適用可能なパラメータを適用した後にのみ可能です-s
。-s
修飾子が次の形式で適用されるたびに、-v
まったく同じパラメータが印刷されます-s|...|...|p
。p
"%s>>%s\n",元のパス名、新しいパス名
././
したがって、上記では、そうでなければ表示されないリストとリストを分離します。今仕事はとても簡単になりました。皆さんも同意してください。このタイプのデータを適用する方法については、読者が決定するようにします。ln
とても簡単なはずですがあえてこれまでする必要もない。
実際、その仕様は、pax
ユーザー、グループ、リンクデータ、ファイル名、ファイルソースなどの項目を変更するために、cliオプションを使用して読み取りまたは書き込み中にアーカイブを変更できるようにすることです。これらは非常に強力なファイル解析ツールです。しかし、私が知っている実装に最も近いのはGNUであり、部分的にのみ可能です。ヘッダーの種類に影響を与える方法が見つかりませんでした。ある程度それを行うことができますが、cliオプションを使用すると、アーカイブ自体で正規表現を使用することはあまり難しくありませんが、それは言葉です。このエントリにはヘッダフィールドがあります。r
w
pax
tar
...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
…まあ、誰が見ているのか知ります。