创建一个在bash脚本命令 [英] Creating a which command in bash script
问题描述
有关的转让,我应该创建一个名为 my_which.sh
脚本,将做同样的事情,Unix命令,但不要使用它循环中,如果超过。我也不允许它调用我的脚本。
我是全新到这一点,并且已经阅读教程,但我很困惑如何启动pretty。不这
只列出一个命令的路径名?
如果是这样,我将如何去而不调用显示正确的路径名其中,并在使用的if语句?循环和
例如,如果我跑我的脚本,它将回声%
并等待输入。但后来我怎么把这一寻找的目录?因此,它是这样的?
#!/斌/庆典
路径=('回声$ PATH`)
呼应-n%
答阅读
因为我在$ PATH
做
如果[-d $ i];然后
回声$我
科幻
DONE
我想AP preciate任何帮助,甚至任何启动教程,可以帮助我得到这个开始。我很诚实,我应该如何实现这个非常困惑。
-
分裂您的
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
设置和非空的。 -
通过这种拆分
PATH
,我们将使用一个for循环来检查是否参数可以在指定的目录中找到。请注意,这应该做只有当参数不包含/
字符!这也是一些其他的答案错过。 -
我的版本
这
处理一个独特的选项-a
的打印所有匹配的路径名每个参数的的。否则,只有第一场比赛被打印出来。我们必须考虑到这一点。 -
我该版本处理以下退出状态:
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.
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 ifPATH
ends with a trailing:
, then it is understood that current directory should be inPATH
. While this is dangerous and not recommended, we must also take it into account if we want to mimicwhich
. Without this trailing colon, aPATH
like/bin:/usr/bin:
would be split intodeclare -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.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.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.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屋!