Bash Shell指定位置查找文件

Bash Shell指定位置查找文件,你需要执行、读入(source)或读取某个文件,但该文件位于 $PATH 之外的其他位置。

source 本身是 bash shell 的内建命令,能够在当前 shell 的上下文中读取并执行指定文件中的命令。source 一词有时候也作为动词使用,目前尚无较好的统一译法,本文中选择将其译为“读入”。

解决方案

如果打算读入的某个文件位于 $PATH 所列路径之中,直接读入就行了。如果设置了 shell 选项 sourcepath(默认启用),bash 的内建命令 source(该命令还有另一个 POSIX 名称 .,虽然够简短且易于输入,但确实容易漏看)会搜索 $PATH

source myfile

如果想要仅在某个文件位于 $PATH 所列路径之中且可执行时才执行该文件,同时 bash 版本为 2.05b 或更高,可以用 type -P 来搜索 $PATH。和 which 命令不同,type -P 只会在找到文件时才产生输出,这使其更易于在下列情况中使用:

LS=$(type -P ls)
[ -x "$LS" ] && $LS

# --或者--

LS=$(type -P ls)
if [ -x "$LS" ]; then
    : commands involving $LS here
fi

如果需要查找可能包括 $PATH 在内的多个位置,可以使用 for 循环。要想搜索 $PATH 中的各个部分,使用变量替换运算符 ${variable//pattern/replacement} 将所有的 : 分隔符替换成空格,使之成为一个个独立的单词,然后用 for 迭代单词列表。具体做法如下所示。

for path in ${PATH//:/ }; do
    [ -x "$path/ls" ] && $path/ls
done

# --或者--    
for path in ${PATH//:/ } /opt/foo/bin /opt/bar/bin; do
    [ -x "$path/ls" ] && $path/ls
done

如果文件未在 $PATH 所列出的路径中,而是在其他位置,甚至连名字都可能不一样,那么可以在 for 语句中列出所有的完整路径。

for file in /usr/local/bin/inputrc /etc/inputrc ~/.inputrc; do
    [ -f "$file" ] && bind -f "$file" && break  # 使用找到的第一个文件
done

根据需要执行其他测试。例如,你可能想在登录时使用 screen(如果系统中有该命令)。

for path in ${PATH//:/ }; do
    if [ -x "$path/screen" ]; then
        # 如果screen(1)存在且可执行:
        for file in /opt/bin/settings/run_screen ~/settings/run_screen; do
            [ -x "$file" ] && $file && break # 执行找到的第一个可执行文件
        done
    fi
done

讨论

用 for 语句迭代所有的可能位置看起来有些杀鸡用牛刀了,但其实这种用法非常灵活,允许你搜索所需要的任何位置、进行任何测试,并对找到的文件执行任何操作。通过将 $PATH 中的每个 : 替换成空格,可以形成for 语句所要求的以空白字符作为分隔的单词列表(任何以空白字符分隔的列表都管用)。根据需要灵活运用该技术,能够帮你编写出一些对文件位置适应性颇高的 shell 脚本,不仅非常灵活,而且具备可移植性。

也许你想通过设置 $IFS=':' 来直接解析 $PATH,而不是将其拆解到 $path 中。这样做当然可以,但涉及一些额外工作,而且也不够灵活。
你可能也想要像下面这样做:

[ -n "$(which myfile)" ] && bind -f $(which myfile)

这里的问题不在于文件存在时,而在于文件不存在时。which 命令在不同系统上行为各异。Red Hat 的 which 命令其实是一个别名,设置了各种命令行选项,如果其参数也是别名,则可以提供与该参数相关的细节信息;指定的参数不存在时,则返回消息,表明未查找到(Debian 或 FreeBSD 上的 which 不会这么做)。要是在 NetBSD 上尝试上面这行,你会得到 no myfile in /sbin /usr/sbin /bin /usr/bin /usr/pkg/sbin /usr/pkg/bin /usr/X11R6/ bin /usr/ local/sbin /usr/local/bin,这不会是你想看到的。

这种情况下,command 命令也值得留意。该命令出现的时间早于 type -P,有时也许能派上用场。

Red Hat Enterprise Linux 4.x 的行为与以下类似。

$ alias which
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

$ which rd
alias rd='rmdir'
        /bin/rmdir

$ which ls
alias ls='ls --color=auto -F -h'
        /bin/ls

$ which cat
/bin/cat

$ which cattt
/usr/bin/which: no cattt in (/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/
X11R6/bin:/home/jp/bin)

$ command -v rd
alias rd='rmdir'

$ command -v ls
alias ls='ls --color=auto -F -h'

$ command -v cat
/bin/cat

Debian 和 FreeBSD(但不包括 NetBSD 或 OpenBSD)的行为与以下类似。

$ alias which
-bash3: alias: which: not found

$ which rd

$ which ls
/bin/ls

$ which cat
/bin/cat

$ which cattt

$ command -v rd
-bash: command: rd: not found

$ command -v ls
/bin/ls

$ command -v cat
/bin/cat

$ command -v ll
alias ll='ls -l'

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!