首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tcl中的二级符号链路跟踪函数

Tcl中的二级符号链路跟踪函数
EN

Stack Overflow用户
提问于 2014-03-12 23:26:20
回答 2查看 1.3K关注 0票数 0

我要做的事情的结果是编写一个相当于以下shell的Tcl函数:

代码语言:javascript
复制
get_real_home () {
    dirname $(ls -l $(ls -l $(which "$1") | awk '{print $NF}') | awk '{print $NF'})
}

简而言之,这给了我包含实际二进制文件的目录的名称,当我给它一个由Debian替代系统管理的程序的名称时,它遵循一个符号链接(通常是在/usr/bin中),指向/etc/alternatives/中的另一个符号链接,它指向当前正在使用的替代程序的可执行文件(或任何其他)。例如:

代码语言:javascript
复制
$ get_real_home java
/usr/lib/jvm/java-6-openjdk-amd64/jre/bin

我之所以要这样做,是因为我使用环境模块 (其“本机语言”是Tcl )来管理许多编译器、解释器和库的环境设置(主要是PATHLD_LIBRARY_PATH)。这个实用程序很好地成为了集群的一个事实上的标准。

尤其是对于Java (在有许多替代方案的地方),可以通过一个环境模块模块将环境(例如JAVA_HOME)设置为当前Debian替代方案的正确值,该模块将“知道”当前Debian替代方案的位置。为此,上面的符号链接追逐器非常方便。

当然,我可以把我已经拥有的(上面)放在一个shell脚本中,然后从环境模块中的Tcl中调用它:一个实用的,如果不优雅的解决方案。我更喜欢更好的“本地”Tcl解决方案,但由于我对Tcl完全不了解,我很难做到这一点,尽管它看起来应该是微不足道的。

我肯定这对懂Tcl的人来说是微不足道的,但那不是我。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-03-13 01:52:23

file normalize命令使这几乎毫不费力。

代码语言:javascript
复制
set javaBinDir [file dirname [file normalize {*}[auto_execok java]]]

( auto_execok命令是一个Tcl库过程,它使用Gipsy魔术来计算如何运行给定的程序。对于java程序,它等同于exec which;对于shell构建来说,它更复杂。它返回一个列表,在本例中是一个单例。我正在展开它,以防你有一个有空格的目录,或者一些不平衡的大括号。不太可能的…)

如果目标本身是一个链接,则需要做更多的工作。

代码语言:javascript
复制
set java [file normalize [lindex [auto_execok java] 0]]
while {[file type $java] eq "link"} {
    # Ought to check for link loops...
    set java [file normalize [file join [file dirname $java] [file readlink $java]]]
}
puts "java really resolves to $java"

file normalize不会自动为您做这件事,因为您可能希望引用链接本身,而不是它所引用的内容。幸运的是,当提供相对组件和绝对组件时,file join做了正确的事情;当我在一个(模拟的)示例中尝试它时,这似乎是有效的。

票数 2
EN

Stack Overflow用户

发布于 2014-03-13 03:06:29

所以,几个小时后,我会回答我自己的问题。这是冗长的,但它有效。下面给出了作为命令调用时我想要的答案,尽管它不会像那样使用。

代码语言:javascript
复制
#!/usr/bin/env tclsh

# Equivalent to shell "which", returning the first occurence of its
# argument, cmd, on the PATH:
proc which {cmd} {
    foreach dir [split $::env(PATH) :] {
        set fqpn $dir/$cmd
        if { [file exists $fqpn] } {
            return $fqpn
        }
    }
}

# True if 'path' exists and is a symbolic link:
proc is_link {path} {
    return [file exists $path] && [string equal [file type $path] link]
}

# Chases a symbolic link until it resolves to a file that
# isn't a symlink:
proc chase {link} {
    set max_depth 10 ; # Sanity check
    set i 0
    while { [is_link $link] && $i < $max_depth } {
        set link [file link $link]
        incr i
    }
    if { $i >= $max_depth } {
        return -code error "maximum link depth ($max_depth) exceeded"
    }
    return $link
}

# Returns the "true home" of its argument, a command:
proc get_real_home {cmd} {
    set utgt [chase [which $cmd]]    ; # Ultimate target
    set home [file dirname $utgt]    ; # Directory containing target
    if { [string equal bin [file tail $home]] } {
        set home [file dirname $home]
    }
    return $home
}

# Not worried about command-line argument validation because
# none of the above will be used in a command context
set cmd  [lindex $argv 0]       ; # Command
set home [get_real_home $cmd]   ; # Ultimate home
puts "$cmd -> $home"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22366001

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档