シンボリックリンク再帰で中間体を見つける方法は?

シンボリックリンク再帰で中間体を見つける方法は?

絶対シンボリックリンクターゲットを出力する非再帰readlink -f/代替方法はありますか?realpathより多くのPOSIX互換ソリューションも歓迎します。

シェルスクリプトには次の関数ブロックがあります。

set FILES
# addFile adds a file to the FILES list. If file is a symlink,
# it will also find and add the destination.
addFile() {
    file="$1"
    # Check if file is already included in list
    echo "$FILES" | grep -q "$file" && return
    FILES="$FILES $file"
    if [ -L $file ]; then
        addFile $(realpath $file)
        #addFile $(readlink $file)
    fi
}

私はファイルシステムからバイナリとライブラリファイルを収集するスクリプトでこの関数を使用しています。ただし、このコードには問題があると予想されます。

  1. 最初の試みは成功しましたが、readlink相対的なシンボリックリンク検証パスを返したため、そのパス$fileで実行されたすべての操作は失敗しました。 (現在コメントされていますが、まだコードにあります)(以下の小さな編集を参照)
  2. その後、realpath提案どおりに使用しましたman readlink。これでほとんど使用する準備が整いました。

今私がしたいことはうまくいっています。しかし、最終的な結果は、initramfsのすべてのバイナリ、ライブラリ、およびシンボリックリンクをコピーすることです。再帰シンボリックリンクがある場合は、中間シンボリックリンクではなく、最上位レベルと宛先のみが含まれます。したがって、シンボリックリンクが切断されました。

ヴァイオリンこの問題を示すために。link-to-link1ポイントlink1、ポイントですfile1。最終結果link1が失われ、link-to-link1破損しています。

質問を明確に修正してください。

次のシンボリックリンクセットで上記の関数を実行するとき:

# Contents of ~/test/src
file0
file1
link0 -> file0
link0.1 -> file0
link1 -> file1
link-to-link1 -> link1

そして:

copy="link-to-link1 link0 link0.1"
for sf in $copy; do
    addFile ~/test/src/$sf
done;
cp -av $FILES ~/test/dst

$copy3つのリンクと2つのファイルのみがコピーされていることを確認できます。しかし、中間リンクlink1がありlink-to-link1ません。

link1私もその台本を探したいです。このスクリプトが実行される環境では、ファイルとシンボリックリンクの場所が絶対的でなければならないことに注意してください。

マイナーな編集

次へ追加別のヴァイオリン相対パスの失敗を示すためにreadlink.を使用すると、シンボリックリンクのみがコピーされ、宛先がありません。

答え1

私が正しく理解したら、与えられた例ではlink1ファイルが欲しいでしょうlink-to-link1findGNUと-printf以下を使用して取得できます%l

$ find . -type l -printf '%p -> %l\n'
./link0.1 -> file0
./link1 -> file1
./link0 -> file0
./link-to-link1 -> link1

link1出力に絶対パスが必要なので、/path/to/link-to-link1/を含めて実行するディレクトリにすることができますcdlink-to-link1readlinkrealpath

(
cd "$(dirname "$file")"
realpath -s "$(readlink "$file")"
)

realpath -sシンボリックリンクは確認されませんが、絶対パスは印刷されます。

たとえば、

~ file=/tmp/foo/link-to-link1
~ (cd "$(dirname "$file")"; realpath -s "$(readlink "$file")")
/tmp/foo/link1

これは絶対パスを持つリンクにも当てはまります。

~ file=/tmp/foo/link2
~ ln -sfv /tmp/foo/link1 "$file"
'/tmp/foo/link2' -> '/tmp/foo/link1'
~ (cd "$(dirname "$file")"; realpath -s "$(readlink "$file")")
/tmp/foo/link1

関連情報