web-dev-qa-db-ja.com

Linux:特定の「オリジナル」ファイルのすべてのシンボリックリンクを見つけますか? (リバース 'readlink')

次のコマンドラインスニペットを検討してください。

$ cd /tmp/
$ mkdir dirA
$ mkdir dirB
$ echo "the contents of the 'original' file" > orig.file
$ ls -la orig.file 
-rw-r--r-- 1 $USER $USER 36 2010-12-26 00:57 orig.file

# create symlinks in dirA and dirB that point to /tmp/orig.file:

$ ln -s $(pwd)/orig.file $(pwd)/dirA/
$ ln -s $(pwd)/orig.file $(pwd)/dirB/lorig.file
$ ls -la dirA/ dirB/
dirA/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:57 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:57 orig.file -> /tmp/orig.file

dirB/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:58 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:58 lorig.file -> /tmp/orig.file

この時点で、readlinkを使用して「オリジナル」とは何かを確認できます(まあ、ここでの通常の用語は「ターゲット」または「ソース」のどちらかです。まあ、だから私はそれを単に「オリジナル」と呼ぶ)シンボリックリンクのファイル、すなわち.

$ readlink -f dirA/orig.file 
/tmp/orig.file
$ readlink -f dirB/lorig.file 
/tmp/orig.file

...しかし、私が知りたいのは-「元の」ファイルで実行でき、それを指すすべてのシンボリックリンクを見つけることができるコマンドはありますか?言い換えれば、(疑似)のようなものです:

$ getsymlinks /tmp/orig.file
/tmp/dirA/orig.file 
/tmp/dirB/lorig.file

コメントありがとうございます、

乾杯!

47
sdaau

ターゲットファイルには、どのソースファイルがそれを指しているかに関する情報が含まれていないため、このコマンドは見たことがなく、簡単な作業ではありません。

これは「ハード」リンクに似ていますが、少なくともそれらは常に同じファイルシステム上にあるため、find -inodeそれらをリストします。ソフトリンクはファイルシステムを横断できるため、より問題があります。

あなたがしなければならないことは基本的にls -al階層全体のすべてのファイルで、grepを使用して-> /path/to/target/file

たとえば、これは私のシステムで実行したものです(読みやすいようにフォーマットされています-実際の出力では、最後の2行は実際にはone行にあります):

pax$ find / -exec ls -ald {} ';' 2>/dev/null | grep '\-> /usr/share/applications'
lrwxrwxrwx 1 pax pax 23 2010-06-12 14:56 /home/pax/applications_usr_share
                                         -> /usr/share/applications
30
paxdiablo

GNU findを使用すると、ファイルにハードリンクまたはシンボリックリンクされているファイルが検索されます。

find -L /dir/to/start -samefile /tmp/orig.file
135

シンボリックリンクは、特定の宛先を指しているものを追跡しません。したがって、次のように、各シンボリックリンクが目的の宛先を指しているかどうかを確認するよりも良い方法はありません。

for i in *; do
    if [ -L "$i" ] && [ "$i" -ef /tmp/orig.file ]; then
        printf "Found: %s\n" "$i"
    fi
done
2
jilles

これが私が思いついたものです。これを_readlink -f_を持たないOS Xで実行しているため、ヘルパー関数を使用して置き換える必要がありました。適切な_readlink -f_があれば、代わりにそれを使用できます。また、この場合、while ... done < <(find ...)の使用は厳密には必要ありません。単純な_find ... | while ... done_が機能します。しかし、ループ内で変数を設定するようなことをしたい場合(一致するファイルの数など)、whileループがサブシェルで実行されるため、パイプバージョンは失敗します。最後に、_find ... -type l_を使用しているため、ループはシンボリックリンクでのみ実行され、他の種類のファイルでは実行されないことに注意してください。

_# Helper function 'cause my system doesn't have readlink -f
readlink-f() {
    orig_dir="$(pwd)"
    f="$1"
    while [[ -L "$f" ]]; do
        cd "$(dirname "$f")"
        f="$(readlink "$(basename "$f")")"
    done
    cd "$(dirname "$f")"
    printf "%s\n" "$(pwd)/$(basename "$f")"
    cd "$orig_dir"
}

target_file="$(readlink-f "$target_file")" # make sure target is normalized

while IFS= read -d '' linkfile; do
    if [[ "$(readlink-f "$linkfile")" == "$target_file" ]]; then 
        printf "%s\n" "$linkfile"
    fi
done < <(find "$search_dir" -type l -print0)
_
0
Gordon Davisson

Gordon Davissonのコメントに触発されました。これは別の答えに似ていますが、execを使用して目的の結果を得ました。元のファイルの場所を知らなくてもシンボリックリンクを見つけることができるものが必要でした。

find / -type l -exec ls -al {} \; | grep -i "all_or_part_of_original_name"
0
Jer