如何检测使用通配符(星号*)作为shell脚本的参数?

kof*_*cii 3 unix linux shell

在我的脚本中,如何区分何时使用星号通配符而不是强类型参数?

这个

# myscript *
Run Code Online (Sandbox Code Playgroud)

由此

# myscript p1 p2 p3 ... (where parameters are unknown number)
Run Code Online (Sandbox Code Playgroud)

Tom*_*son 7

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函数,并要求您的用户使用别名而不是脚本.但如果你能做到这一点,它应该有效.

我应该补充一点,我在很大程度上依赖于灿烂的西蒙·塔特姆的文章" 魔法别名:伯恩壳中分层漏洞 ".


jed*_*rds 7

我有一个类似的问题,但不是检测用户何时使用通配符调用脚本,我只是想阻止使用通配符,并传递字符串预扩展.

如果你想检测汤姆的解决方案很棒,但我宁愿阻止.换句话说,如果我有一个名为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)

而不是一个额外的包装函数.

对于比必要的写法更长的时间,请在此处查看我的帖子.