在我的脚本中,如何区分何时使用星号通配符而不是强类型参数?
此
# myscript *
来自这个
# myscript p1 p2 p3 ... (where parameters are unknown number)
答案 0 :(得分:7)
shell扩展了通配符。在运行脚本时,通配符已经扩展,并且脚本无法判断参数是通配符还是显式列表。
这意味着您的脚本需要其他非脚本的帮助。具体来说,在命令行处理之前运行的东西。那个东西是别名。这是你的别名
alias myscript='set -f; globstopper /usr/bin/myscript'
这样做是设置一个名为'myscript'的别名,所以当有人输入'myscript'时,这就是运行的东西。别名做了两件事:首先,它用set -f
关闭通配符扩展,然后运行一个名为globstopper的函数,传入脚本的路径,以及其余的命令行参数。
那是什么是globstopper函数?这样:
globstopper() {
if [[ "$2" == "*" ]]
then echo "You cannot use a wildcard"
return
fi
set +f
"$@";
}
这个功能做了三件事。首先,它检查脚本的参数是否是通配符(警告:它只检查第一个参数,它只检查它是否是一个简单的星;延伸它以覆盖更多的情况留下作为练习读者)。其次,它重新开启了通配符扩展。最后,它运行原始命令。
为此,您需要能够在用户的shell中设置别名和shell功能,并要求您的用户使用别名,而不是脚本。但如果你能做到这一点,就应该有效。
我应该补充一点,我在这里严重依赖金碧辉煌的西蒙·塔特姆的文章“Magic Aliases: A Layering Loophole in the Bourne Shell”。
答案 1 :(得分:7)
我有一个类似的问题,但是当用户使用通配符调用脚本时,检测,而不是阻止使用通配符,并通过字符串预扩展。
如果你想要发现,Tom's solution很棒,但我宁愿阻止。换句话说,如果我有一个名为findin的脚本看起来像
#!/bin/bash
echo "[${1}]"
并使用以下方式运行:
$ findin *
我希望输出只是
[*]
要做到这一点,你可以通过
命名findinalias findin='set -f; /path/to/findin'
但是,您可以为会话的其余部分设置shell选项。这可能会破坏许多不期望这样的程序(例如ls -lh * .py)。您可以通过键入
来验证这一点echo $-
在控制台中。如果看到f,则设置该选项。
您可以通过键入
手动清除该选项set +f
在每个findin实例之后,但这会变得单调乏味。
由于shell脚本产生子shell并且你无法从脚本中清除标志(set + f),我提出的解决方案如下:
g(){ /usr/local/bin/findin "$@"; set +f; }
alias findin='set -f; g'
注意:'g'可能不是该函数的最佳名称,因此我们鼓励您更改它。
最后,您可以通过执行以下操作来概括:
reset_expansion(){ CMD="$1"; shift; $CMD "$@"; set +f; }
alias findin='set -f; reset_expansion /usr/local/bin/findin'
这样,您希望扩展禁用的另一个脚本只需要一个额外的别名,例如
alias newscript='set -f; reset_expansion /usr/local/bin/newscript'
而不是额外的包装函数。
如果时间长于必要的写作,请参阅my post here。
答案 2 :(得分:3)
答案 3 :(得分:1)
$arg_num == ***; // detects *(literally anything since it's a global wildcard)
$arg_num == *_*; // detects _
这是一个使用_
的例子for i in $*
do
if [[ "$i" == *_* ]];
then echo $i;
fi
done
输出 ./ bash test * test2 _
_
输出 ./ bash test * test2 使用*********而不是*** *
test
bash
pass.rtf
test2
_
注意:*在bash中是如此全局,以至于它打印出与该描述相匹配的文件,或者在我这个未使用过的桌面上的文件中。我希望我能给你一个更好的答案,但最好选择使用其他*或其他脚本语言。
答案 4 :(得分:1)
附录
我在寻找命令行计算器的解决方法时找到了这篇文章:
alias c='set -f; call_clc'
where "call_clc" is the function: "function call_clc { clc "$*"; set +f; }"
and "clc" is the script
#!/bin/bash
echo "$*" | sed -e 's/ //g' >&1 | tee /dev/tty | bc
我需要'set -f
'和'set +f
'才能使'c 4 * 3'等输入正常工作,
因此前后有白色空间的星号,
为了防止狂欢的崩溃。
更新:上一个版本“alias c='set -f; clc "$*"; set+f;'
”无效
因为某些原因,在两次调用命令“c 4 * 4”后给出了正确的结果。
有人知道为什么会这样吗?
答案 5 :(得分:0)
如果这是您认为必须做的事情,或许:
# if the number of parms is not the same as the number of files in cwd
# then user did not use *
dir_contents=(*)
if [[ "${#@}" -ne "${#dir_contents[@]}" ]]; then
used_star=false
else
# if one of the params is not a file in cwd
# then user did not use *
used_star=true
for f; do [[ ! -a "$f" ]] && { used_star=false; break; }; done
fi
unset dir_contents
$used_star && echo "used star" || echo "did not use star"
如果用户实际使用星号或者用户以任何顺序手动输入目录内容,这将会回显“使用过的星号”。