创建一个在bash脚本命令 [英] Creating a which command in bash script

查看:98
本文介绍了创建一个在bash脚本命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关的转让,我应该创建一个名为 my_which.sh 脚本,将做同样的事情,Unix命令,但不要使用它循环中,如果超过。我也不允许它调用我的脚本。

我是全新到这一点,并且已经阅读教程,但我很困惑如何启动pretty。不只列出一个命令的路径名?

如果是这样,我将如何去而不调用显示正确的路径名其中,并在使用的if语句?循环和

例如,如果我跑我的脚本,它将回声%并等待输入。但后来我怎么把这一寻找的目录?因此,它是这样的?

 #!/斌/庆典
路径=('回声$ PATH`)
呼应-n%
答阅读
因为我在$ PATH

    如果[-d $ i];然后
       回声$我
    科幻
DONE

我想AP preciate任何帮助,甚至任何启动教程,可以帮助我得到这个开始。我很诚实,我应该如何实现这个非常困惑。


解决方案

  1. 分裂您的 PATH 变量的安全的。这是为了分割在分隔符串的一般方法,即100%的安全方面的任何可能的字符(包括新行):

      IFS =:读-r -d''-a路径< ≤(printf的'%S:\\ 0'$ PATH)

    我们人为添加,因为如果 PATH 后面有个结束:,那么据了解,当前目录应是 PATH 。虽然这是危险的,不推荐,我们还必须考虑到这一点,如果我们想模仿。如果没有这个尾随冒号,一个 PATH / bin中:在/ usr / bin中:将被分成

     宣布-a路径=([0] =/ BIN[1] =的/ usr / bin中)'

    而这个结尾冒号结果数组是:

     宣布-a路径=([0] =/ BIN[1] =在/ usr / bin中[2] =)

    这是一个细节,其他的答案错过。当然,我们会做这仅 PATH 设置和非空的。


  2. 通过这种拆分 PATH ,我们将使用一个for循环来检查是否参数可以在指定的目录中找到。请注意,这应该做只有当参数不包含 / 字符!这也是一些其他的答案错过。


  3. 我的版本处理一个独特的选项 -a 打印所有匹配的路径名每个参数的的。否则,只有第一场比赛被打印出来。我们必须考虑到这一点。


  4. 我该版本处理以下退出状态:


      0,如果所有指定的命令被发现和可执行   1,如果一个或多个指定的命令不存在或无法执行   2如果指定了无效的选项


    我们会处理这一点。


我想下面的模仿,而忠实的行为,我的(和它的纯粹的Bash):

 #!/斌/庆典show_usage(){
    printf的用法:%s的[-a] ARGS \\ n'$ 0
}illegal_option(){
    printf的>和2'非法选项 - %S \\ n'$ 1
    show_usage
    2号出口
}check_arg(){
    如果[[-f $ 1安培;&安培; -x $ 1]];然后
        printf的'%s的\\ n'$ 1
        返回0
    其他
        返回1
    科幻
}#管理选项show_only_one =真而(($#));做
    [[$ 1 = - ]]&放大器;&安培; {移位;打破; }
    [[$ 1 = - *]] ||打破
    选择= $ {1# - }
    而[[$选择]];做
        案例$选择在
            (A *)show_only_one = FALSE;选择= $ {#选择?} ;;
            (*)illegal_option$ {选择:0:1};;
        ESAC
    DONE
    转移
DONE#如果没有参数向左或空路径,以返回code 1退出
(($#))|| 1号出口
[[$ PATH] || 1号出口#拆分路径
IFS =:读-r -d''-a路径< ≤(printf的'%S:\\ 0'$ PATH)RET = 0
在参数#循环
arg的;做
    #检查ARG是否包含一个斜杠
    如果[[$ ARG = * / *];然后
        check_arg$ ARG|| RET = 1
    其他
        this_ret = 1
        在$ {路径[@]}P;做
            如果check_arg$ {号码: - } / $ ARG然后
               this_ret = 0
               $ show_only_one与&&放大器;打破
            科幻
        DONE
        ((this_ret == 1))及&放大器; RET = 1
    科幻
DONE退出$ RET

要测试一个参数是否为可执行文件或不是,我检查它是否是一个正常的文件 1 这是可执行文件:

  [-f $ ARG和放大器;&安培; -x $ ARG]

我想这是接近我的的行为。


1 作为@ mklement0指出的(感谢!)在 -f 测试中,当应用对一个符号链接,测试的类型符号链接的的目标

For an assignment, I'm supposed to create a script called my_which.sh that will "do the same thing as the Unix command, but do it using a for loop over an if." I am also not allowed to call which in my script.

I'm brand new to this, and have been reading tutorials, but I'm pretty confused on how to start. Doesn't which just list the path name of a command?

If so, how would I go about displaying the correct path name without calling which, and while using a for loop and an if statement?

For example, if I run my script, it will echo % and wait for input. But then how do I translate that to finding the directory? So it would look like this?

#!/bin/bash
path=(`echo $PATH`)
echo -n "% "
read ans
for i in $path
do
    if [ -d $i ]; then
       echo $i
    fi
done

I would appreciate any help, or even any starting tutorials that can help me get started on this. I'm honestly very confused on how I should implement this.

解决方案

  1. Split your PATH variable safely. This is a general method to split a string at delimiters, that is 100% safe regarding any possible characters (including newlines):

    IFS=: read -r -d '' -a paths < <(printf '%s:\0' "$PATH")
    

    We artificially added : because if PATH ends with a trailing :, then it is understood that current directory should be in PATH. While this is dangerous and not recommended, we must also take it into account if we want to mimic which. Without this trailing colon, a PATH like /bin:/usr/bin: would be split into

    declare -a paths='( [0]="/bin" [1]="/usr/bin" )'
    

    whereas with this trailing colon the resulting array is:

    declare -a paths='( [0]="/bin" [1]="/usr/bin" [2]="" )'
    

    This is one detail that other answers miss. Of course, we'll do this only if PATH is set and non-empty.

  2. With this split PATH, we'll use a for-loop to check whether the argument can be found in the given directory. Note that this should be done only if argument doesn't contain a / character! this is also something other answers missed.

  3. My version of which handles a unique option -a that print all matching pathnames of each argument. Otherwise, only the first match is printed. We'll have to take this into account too.

  4. My version of which handles the following exit status:

       0      if all specified commands are found and executable
    
       1      if one or more specified commands is nonexistent or not executable
    
       2      if an invalid option is specified
    

    We'll handle that too.

I guess the following mimics rather faithfully the behavior of my which (and it's pure Bash):

#!/bin/bash

show_usage() {
    printf 'Usage: %s [-a] args\n' "$0"
}

illegal_option() {
    printf >&2 'Illegal option -%s\n' "$1"
    show_usage
    exit 2
}

check_arg() {
    if [[ -f $1 && -x $1 ]]; then
        printf '%s\n' "$1"
        return 0
    else
        return 1
    fi
}

# manage options

show_only_one=true

while (($#)); do
    [[ $1 = -- ]] && { shift; break; }
    [[ $1 = -?* ]] || break
    opt=${1#-}
    while [[ $opt ]]; do
        case $opt in
            (a*) show_only_one=false; opt=${opt#?} ;;
            (*) illegal_option "${opt:0:1}" ;;
        esac
    done
    shift
done

# If no arguments left or empty PATH, exit with return code 1
(($#)) || exit 1
[[ $PATH ]] || exit 1

# split path
IFS=: read -r -d '' -a paths < <(printf '%s:\0' "$PATH")

ret=0
# loop on arguments
for arg; do
    # Check whether arg contains a slash
    if [[ $arg = */* ]]; then
        check_arg "$arg" || ret=1
    else
        this_ret=1
        for p in "${paths[@]}"; do
            if check_arg "${p:-.}/$arg"; then
               this_ret=0
               "$show_only_one" && break
            fi
        done
        ((this_ret==1)) && ret=1
    fi
done

exit "$ret"

To test whether an argument is executable or not, I'm checking whether it's a regular file1 which is executable with:

[[ -f $arg && -x $arg ]]

I guess that's close to my which's behavior.


1 As @mklement0 points out (thanks!) the -f test, when applied against a symbolic link, tests the type of the symlink's target.

这篇关于创建一个在bash脚本命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆