linux 如何将通过“which”命令找到的路径显示为实际可执行文件的符号链接树?

busg9geu  于 2023-03-17  发布在  Linux
关注(0)|答案(2)|浏览(112)

我对shell脚本的所有特性都不是很熟悉,所以如果我想列出一个命令的实际可执行文件的完整链接链路径,我目前正在逐行手动键入:

~ $ which rename
/usr/bin/rename
~ $ file /usr/bin/rename
/usr/bin/rename: symbolic link to /etc/alternatives/rename
~ $ file /etc/alternatives/rename
/etc/alternatives/rename: symbolic link to /usr/bin/file-rename
~ $ file /usr/bin/file-rename
/usr/bin/file-rename: Perl script text executable

我想使用一个命令来代替这种多次复制/粘贴工作,该命令的名称如下:

~ $ whichf rename

提供以下输出:

rename
 -> symbolic link to /etc/alternatives/rename
   -> symbolic link to /usr/bin/file-rename 
     -> Perl script text executable

是否有人已经编写了这样的命令,并可以在这里共享它,这样就不需要重新发明轮子?
我已经想出了下面的代码:

~ $ s0=$s;echo $s0; s1=$(which rename);echo "  -> $s1";s2=$(file $s1); echo "    -> ${s2##*:}"

得到:

rename
  -> /usr/bin/rename
    ->  symbolic link to /etc/alternatives/rename

但这只给出了整个路径的前两行。

okxuctiv

okxuctiv1#

使用readlink

#!/usr/bin/env bash

whichf(){
    local prefix="  -> " c=$(type -t $1 2>/dev/null) new
    [[ $c = @(alias|builtin|function|keyword) ]] && { echo "$1 is a $c"; return; }
    test -z "$c" && { echo "$1 : not found."; return; }
    c="$(type -p $1)"
    echo "$1"
    while true; do
        echo "$prefix$c"
        new="$(readlink "$c")"
        if  test -z "$new"; then
            echo "  $prefix$(file "$c" | grep -oP '.*: \K.*')"
            break
        fi
        c="$new" prefix="  $prefix"
    done
}

whichf rename
c9x0cxw0

c9x0cxw02#

下面的代码使用whichfile命令沿着shell字符串操作和一个循环,该循环能够沿着符号链接的路径到达实际的可执行文件,从而提供您所要求的功能:

#!/usr/bin/env bash
whichf ( ) {
    # Custom 'which' named 'whichf' able to go down the chain of links 
    # to the actual executable (by Claudio 2023-03-11):
    s0=$1
    sb='  '
    echo $s0
    s1=$(which $s0)
    echo "$sb-> $s1"
    if [ ! -e "$s1" ]
    then
       return
    fi
    while : 
    do
        s2=$(file $s1 2>/dev/null)
        s3=${s2##*:}
        sb="  $sb"
        echo "$sb-> $s3"
        s4=${s3##* }
        if [ ! -e "$s4" ]
        then
            return
        fi
        s1=$s4
    done
}
export whichf
whichf $1

使用它的风险自担,并有乐趣,看看有多深的链接链去命令'重命名':

~ $ whichf rename
rename
  -> /usr/bin/rename
    ->  symbolic link to /etc/alternatives/rename
      ->  symbolic link to /usr/bin/file-rename
        ->  Perl script text executable
~ $

并在它的帮助下发现启动'gnome-terminal'执行一个Python脚本:

~ $ whichf gnome-terminal
gnome-terminal
  -> /usr/bin/gnome-terminal
    ->  Python script, ASCII text executable
~ $

为了完整起见,下面的typef函数代码受另一个答案的启发,但利用type的能力进行了改进,以输出有关shell内置命令的信息:

#!/usr/bin/env bash
typef(){
    local command indent="  -> " fpFName symLinkTarget
    command=$1
    echo $command
    maybe_fpFName="$(type $command 2> /dev/null)" 
    fpFName="${maybe_fpFName#*/}"
    if test -z "$fpFName"; then
        echo "$indent$maybe_fpFName"
        return
    fi
    fpFName="/$fpFName"
    if [ ! -e "$fpFName" ]; then
        echo "$indent$maybe_fpFName"
        return
    fi
    while : ; do
        echo "$indent$fpFName"
        if [ ! -e "$fpFName" ]; then
            break
        fi
        indent="  $indent"
        symLinkTarget=$(readlink "$fpFName")
        if  test -z "$symLinkTarget"; then # symLinkTarget is empty
            echo "$indent$(file "$fpFName" | grep -oP '.*: \K.*')"
            break
        fi
        fpFName="$symLinkTarget" 
    done
}
export typef
typef $1

如果您想知道哪些命令被视为内置命令,请使用它:

~ $ typef echo
echo
  -> echo is a shell builtin
~ $ typef type
type
  -> type is a shell builtin

注意由于whichftypef使用的方法不同,因此可能会产生不同的结果。例如,命令echo由typef报告为内置命令,而由whitef报告为/usr/bin/echo可执行文件。使用type -a echo时,您可以看到echo可以同时是这两种命令。一个内置shell命令,并最终作为可执行文件在搜索路径中出现两次(也作为/bin/echo)。

相关问题