在我的脚本中,如何区分何时使用星号通配符而不是强类型参数?
这个
# myscript *
Run Code Online (Sandbox Code Playgroud)
由此
# myscript p1 p2 p3 ... (where parameters are unknown number)
Run Code Online (Sandbox Code Playgroud)
shell扩展了通配符.到运行脚本时,通配符已经扩展,并且脚本无法判断参数是通配符还是显式列表.
这意味着您的脚本需要其他非脚本的帮助.特别是,在命令行处理之前运行的东西.那个东西是别名.这是你的别名
alias myscript='set -f; globstopper /usr/bin/myscript'
Run Code Online (Sandbox Code Playgroud)
这样做是设置一个名为'myscript'的别名,所以当有人输入'myscript'时,这就是运行的东西.别名做了两件事:首先,它关闭通配符扩展set -f
,然后它运行一个名为globstopper的函数,传入脚本的路径,以及其余的命令行参数.
那么globstopper功能是什么?这个:
globstopper() {
if [[ "$2" == "*" ]]
then echo "You cannot use a wildcard"
return
fi
set +f
"$@";
}
Run Code Online (Sandbox Code Playgroud)
这个功能做了三件事.首先,它检查脚本的参数是否是通配符(警告:它只检查第一个参数,它只检查它是否是一个简单的星;延伸它以覆盖更多的情况留下作为练习读者).其次,它重新开启了通配符扩展.最后,它运行原始命令.
为此,您需要能够在用户的shell中设置别名和shell函数,并要求您的用户使用别名而不是脚本.但如果你能做到这一点,它应该有效.
我应该补充一点,我在很大程度上依赖于灿烂的西蒙·塔特姆的文章" 魔法别名:伯恩壳中的分层漏洞 ".
我有一个类似的问题,但不是检测用户何时使用通配符调用脚本,我只是想阻止使用通配符,并传递字符串预扩展.
如果你想检测汤姆的解决方案很棒,但我宁愿阻止.换句话说,如果我有一个名为findin的脚本
#!/bin/bash
echo "[${1}]"
Run Code Online (Sandbox Code Playgroud)
并运行它:
$ findin *
Run Code Online (Sandbox Code Playgroud)
我希望输出简单
[*]
Run Code Online (Sandbox Code Playgroud)
要做到这一点,你可以只是别名findin
alias findin='set -f; /path/to/findin'
Run Code Online (Sandbox Code Playgroud)
但是,您可以为会话的其余部分设置shell选项.这可能会破坏许多不期望这样的程序(例如ls -lh*.py).您可以通过键入来验证这一点
echo $-
Run Code Online (Sandbox Code Playgroud)
在控制台.如果看到f,则设置该选项.
您可以通过键入手动清除该选项
set +f
Run Code Online (Sandbox Code Playgroud)
在每个findin实例之后,但这将变得乏味和烦人.
由于shell脚本产生子shell并且你无法从脚本中清除标志(set + f),我提出的解决方案如下:
g(){ /usr/local/bin/findin "$@"; set +f; }
alias findin='set -f; g'
Run Code Online (Sandbox Code Playgroud)
注意:'g'可能不是该函数的最佳名称,因此我们鼓励您更改它.
最后,您可以通过执行以下操作来概括:
reset_expansion(){ CMD="$1"; shift; $CMD "$@"; set +f; }
alias findin='set -f; reset_expansion /usr/local/bin/findin'
Run Code Online (Sandbox Code Playgroud)
这样,您希望扩展禁用的另一个脚本只需要一个额外的别名,例如
alias newscript='set -f; reset_expansion /usr/local/bin/newscript'
Run Code Online (Sandbox Code Playgroud)
而不是一个额外的包装函数.