Linux shell,哪个命令扩展为显示链接到实际可执行文件的完整路径

snvhrwxg  于 2023-03-13  发布在  Shell
关注(0)|答案(2)|浏览(405)

我对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

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

~ $ which-chain 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

我不知道如何解决的问题是知道如何继续下去,以便涵盖任何数量的链节的一般情况。
几分钟后......在下一行输出之间编码:

~ $ s0=$s;echo $s0; s1=$(which $s0);echo "  -> $s1";s2=$(file $s1);s3=${s2##*:};echo "    -> $s3";s4=${s3##* };s5=$(file $s4);s6=${s5##*:}; echo "      -> $s6"
rename
  -> /usr/bin/rename
    ->  symbolic link to /etc/alternatives/rename
      ->  symbolic link to /usr/bin/file-rename

...几分钟后...

~ $ s=rename
~ $ s0=$s;echo $s0; s1=$(which $s0);echo "  -> $s1";s2=$(file $s1);s3=${s2##*:};echo "    -> $s3";s4=${s3##* };s5=$(file $s4);s6=${s5##*:}; echo "      -> $s6";s7=${s6##* };s8=$(file $s7);s9=${s8##*:}; echo "        -> $s9"
rename
  -> /usr/bin/rename
    ->  symbolic link to /etc/alternatives/rename
      ->  symbolic link to /usr/bin/file-rename
        ->  Perl script text executable

...现在使用define which-chain命令在另一个命令上尝试:

~ $ s=gnome-terminal
~ $ alias which-chain='s0=$s;echo $s0; s1=$(which $s0);echo "  -> $s1";s2=$(file $s1);s3=${s2##*:};echo "    -> $s3";s4=${s3##* };s5=$(file $s4);s6=${s5##*:}; echo "      -> $s6";s7=${s6##* };s8=$(file $s7);s9=${s8##*:}; echo "        -> $s9"'
~ $ which-chain
gnome-terminal
  -> /usr/bin/gnome-terminal
    ->  Python script, ASCII text executable
      ->  cannot open `executable' (No such file or directory)
        ->  cannot open `directory)' (No such file or directory)

现在试着把它变成一个可以带参数的函数:

~ $ f-which () { s0=$1;echo $s0; s1=$(which $s0);echo "  -> $s1";s2=$(file $s1);s3=${s2##*:};echo "    -> $s3";s4=${s3##* };s5=$(file $s4);s6=${s5##*:}; echo "      -> $s6";s7=${s6##* };s8=$(file $s7);s9=${s8##*:}; echo "        -> $s9" }

但是shell不接受它寻找一些下一行...不知道为什么上面的不起作用...有什么提示吗?

cbeh67ev

cbeh67ev1#


~ $ whichf
下面的函数(哪个文件是实际的可执行文件?)执行请求的作业,扩展标准which命令的功能,以显示指向实际可执行文件的整个链接链:

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 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 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)。

km0tfn4u

km0tfn4u2#

使用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

相关问题