停止shell通配符扩展?


88

有什么方法可以让已编译的命令行程序告诉bash或csh它不想扩展其参数中的任何通配符?

例如,可能需要像这样的shell命令:

foo *

简单地返回该字符的数字ASCII值。

Answers:


117

否。扩展发生在命令实际运行之前。
您只能在运行命令或引用星号之前禁用glob。

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob

3
同样,如果没有什么可扩展的,就没有扩展。即与一个空的pwdecho *只是*
萨姆·布尔萨里斯(Sam boosalis)2014年

7
@sam实际上取决于您如何设置选项。在tldp中: “如果找不到匹配的文件名,并且nullglob禁用了shell选项,则该词保持不变。如果nullglob设置了该选项,但未找到匹配项,则将删除该词。”
克里斯·米德尔顿

谢谢,我应该证明那仅仅是出于观察而不是出于任何理解。
sam boosalis 2015年

@ c00kiemon5ter如何撤消set -f?是unset -f
南G VU

1
@NamGVUset +f
Yngvar Kristiansen

62

虽然命令本身确实不能关闭globing,但用户有可能告诉Unix shell不要glob特定命令。通常,这是通过编辑Shell的配置文件来完成的。假设foo可以在命令路径中找到该命令,则需要将以下内容添加到适当的配置文件中:

对于sh,bash和ksh外壳:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

对于csh和tcsh shell:

alias foo 'set noglob;\foo \!*;unset noglob'

对于zsh shell:

alias foo='noglob foo'

不必使用命令路径。假设命令foo存储在目录〜/ bin中,则上面的内容将变为:

对于sh,bash和ksh外壳:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

对于csh和tcsh shell:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

对于zsh shell:

alias foo='noglob ~/bin/foo'

以上所有内容均使用Apple的OSX 10.9.2进行了测试。注意:复制上面的代码时,请注意删除任何空格。它们可能很重要。

更新:

用户geira指出,在使用bash shell的情况下

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

可以替换为

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

这消除了对函数foo的需要。

一些用于创建此文档的网站:


3
这应该是已被接受的答案,因为它证明确实可以执行OP想要的操作。对于一些更好的bash方法,此链接记录了各种选项: blog.edwards-research.com/2011/05/preventing-globbing
geira 2015年

@geira:有时在发布更好的答案之前就接受了答案。我相信这可能是其中一种情况。我也相信,答案最容易被用户接受。注意:我已将您的输入添加到我的答案中。
David Anderson

@ geira,OP希望编译后的程序与Shell通信;回答说有可能将外壳配置为按命令运行,这是一个有用的答案,我本人也可以接受,但我确实对它是否完全按点存在意见分歧。
查尔斯·达菲

它事实上可以做并不意味着它应该做。使shell的行为偏离用户对选择命令的合理期望,这听起来令人惊讶,而且最终是不受欢迎的。
三胞胎

@tripleee:曾经有一段时间人们期望继电器和真空管。预计会在硬纸板和纸带上打孔。人们拿着计算尺,而不是计算器和电话。我想这对您来说是可取的。那些时候我不太在意。我很高兴看到下一步。
David Anderson

8

扩展在运行程序之前由外壳执行。您的程序不知道是否发生了扩展。

   set -o noglob

会在调用外壳程序中关闭扩展功能,但是您必须调用程序之前执行此操作。

另一种方法是引用您的论据,例如

foo "*"

4
setopt似乎是zsh特定的命令。正如另一位发布者所说,对于bash,您set -o noglob可以禁用通配符扩展。
Wirawan Purwanto

现在修改。谢谢
Brian Agnew

1

当心:如果没有与掩码匹配的名称,bash会按原样传递参数,而不进行扩展!

证明(pa.py是一个非常简单的脚本,只显示其参数):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']

3
不总是。set -o nullglobshopt -s failglob,此行为将发生变化(以两种非常不同的方式)。
Charles Duffy 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.