在C或C++中控制shell命令行通配符扩展 我正在用C++编写一个程序,FoO。它通常在命令行上调用,如下所示: foo *.txt

在C或C++中控制shell命令行通配符扩展 我正在用C++编写一个程序,FoO。它通常在命令行上调用,如下所示: foo *.txt,c++,shell,command-line,unix,wildcard,C++,Shell,Command Line,Unix,Wildcard,我的main以正常的方式接收参数。在许多系统上,argv[1]实际上是*.txt,我必须调用系统例程来进行通配符扩展。但是,在Unix系统上,shell会在调用我的程序之前展开通配符,所有匹配的文件名都将在argv中 假设我想向foo添加一个开关,使其递归到子目录中 foo -a *.txt 将处理当前目录及其所有子目录中的所有文本文件 foo -a *.txt 我不知道这是怎么做到的,因为当我的程序有机会看到-a时,shell已经完成了扩展,用户的*.txt输入丢失了。然而,有一些常见的U

我的main以正常的方式接收参数。在许多系统上,argv[1]实际上是*.txt,我必须调用系统例程来进行通配符扩展。但是,在Unix系统上,shell会在调用我的程序之前展开通配符,所有匹配的文件名都将在argv中

假设我想向foo添加一个开关,使其递归到子目录中

foo -a *.txt
将处理当前目录及其所有子目录中的所有文本文件

foo -a *.txt
我不知道这是怎么做到的,因为当我的程序有机会看到-a时,shell已经完成了扩展,用户的*.txt输入丢失了。然而,有一些常见的Unix程序是这样工作的。他们是怎么做到的

在Unix平台上,如何控制通配符扩展


通过子目录递归只是一个例子。理想情况下,我试图理解控制通配符扩展的一般解决方案。

您的程序对shell的命令行扩展没有影响。将调用哪个程序是在所有扩展完成后确定的,因此以编程方式更改有关扩展的任何内容都为时已晚

另一方面,调用程序的用户可以创建他喜欢的任何命令行。Shell允许您轻松防止通配符扩展,通常是将参数放在单引号中:

program -a '*.txt'
如果您的程序被这样调用,它将收到两个参数-a和*.txt


在Unix上,如果不需要,您应该让用户手动阻止通配符扩展。

您的程序对shell的命令行扩展没有影响。将调用哪个程序是在所有扩展完成后确定的,因此以编程方式更改有关扩展的任何内容都为时已晚

foo -a '*.txt'
另一方面,调用程序的用户可以创建他喜欢的任何命令行。Shell允许您轻松防止通配符扩展,通常是将参数放在单引号中:

program -a '*.txt'
如果您的程序被这样调用,它将收到两个参数-a和*.txt

在Unix上,如果不需要,您应该让用户手动阻止通配符扩展

foo -a '*.txt'
shell在Unix上的部分工作是扩展命令行通配符参数。你可以用引号来阻止它

此外,在Unix系统上,find命令执行您想要的操作:

find . -name '*.txt'
将递归列出当前目录下的所有文件

因此,你可以这样做

foo `find . -name '*.txt'`
shell在Unix上的部分工作是扩展命令行通配符参数。你可以用引号来阻止它

此外,在Unix系统上,find命令执行您想要的操作:

find . -name '*.txt'
将递归列出当前目录下的所有文件

因此,你可以这样做

foo `find . -name '*.txt'`

正如其他答案所说,shell执行通配符扩展,您可以通过在引号中包含参数来阻止它这样做

注意,选项-R和-R通常用于表示递归-参见cp、ls等示例

假设您适当地组织事情,以便将通配符作为通配符传递给您的程序,并且希望执行递归,那么POSIX提供了一些例程来帮助:

-文件树遍历递归访问。 ,-进行文件名匹配和扩展 还有,这与nftw非常相似,但它被标记为“过时”,所以新代码不应该使用它

阿德里安问道:

但是我可以说ls-R*.txt没有单引号,并且可以得到一个递归列表。这是怎么回事

为了使问题适合我计算机上的一个方便位置,让我们回顾一下:

$ ls -F | grep '^m'
makefile
mapmain.pl
minimac.group
minimac.passwd
minimac_13.terminal
mkmax.sql.bz2
mte/
$ ls -R1 m*
makefile
mapmain.pl
minimac.group
minimac.passwd
minimac_13.terminal
mkmax.sql.bz2

mte:
multithread.ec
multithread.ec.original
multithread2.ec
$
因此,我有一个子目录“mte”,其中包含三个文件。我有六个文件的名字以“m”开头

当我键入“ls-R1 m*”时,shell会注意到元字符“*”并使用其等价物glob或wordexp将其扩展到名称列表中:

生成文件 mapmain.pl minimac.群 minimac.passwd minimac_13.0终端 mkmax.sql.bz2 mte 然后shell安排运行带有9个参数的'/bin/ls',程序名,选项-R1,加上7个文件名和终止空指针

ls命令记录递归和单列输出选项,并开始工作。 前6个名称实际上是简单的文件,因此不需要递归。 姓氏是一个目录,所以ls打印它的名称和内容,调用它的等价物nftw来完成这项工作。 在这一点上,它就完成了。 这个未讨论的示例没有显示当存在多个目录时会发生什么,因此上面的描述过度简化了处理过程。 具体来说,ls首先处理非目录名,然后默认情况下按字母顺序处理目录名,并对每个目录进行深度优先扫描。
正如其他答案所说,答案是否定的 hell进行通配符扩展,您可以通过将参数括在引号中来阻止它这样做

注意,选项-R和-R通常用于表示递归-参见cp、ls等示例

假设您适当地组织事情,以便将通配符作为通配符传递给您的程序,并且希望执行递归,那么POSIX提供了一些例程来帮助:

-文件树遍历递归访问。 ,-进行文件名匹配和扩展 还有,这与nftw非常相似,但它被标记为“过时”,所以新代码不应该使用它

阿德里安问道:

但是我可以说ls-R*.txt没有单引号,并且可以得到一个递归列表。这是怎么回事

为了使问题适合我计算机上的一个方便位置,让我们回顾一下:

$ ls -F | grep '^m'
makefile
mapmain.pl
minimac.group
minimac.passwd
minimac_13.terminal
mkmax.sql.bz2
mte/
$ ls -R1 m*
makefile
mapmain.pl
minimac.group
minimac.passwd
minimac_13.terminal
mkmax.sql.bz2

mte:
multithread.ec
multithread.ec.original
multithread2.ec
$
因此,我有一个子目录“mte”,其中包含三个文件。我有六个文件的名字以“m”开头

当我键入“ls-R1 m*”时,shell会注意到元字符“*”并使用其等价物glob或wordexp将其扩展到名称列表中:

生成文件 mapmain.pl minimac.群 minimac.passwd minimac_13.0终端 mkmax.sql.bz2 mte 然后shell安排运行带有9个参数的'/bin/ls',程序名,选项-R1,加上7个文件名和终止空指针

ls命令记录递归和单列输出选项,并开始工作。 前6个名称实际上是简单的文件,因此不需要递归。 姓氏是一个目录,所以ls打印它的名称和内容,调用它的等价物nftw来完成这项工作。 在这一点上,它就完成了。 这个未讨论的示例没有显示当存在多个目录时会发生什么,因此上面的描述过度简化了处理过程。 具体来说,ls首先处理非目录名,然后默认情况下按字母顺序处理目录名,并对每个目录进行深度优先扫描。
我想指出另一种关闭通配符扩展的方法。您可以告诉shell使用noglob选项停止扩展通配符

对于bash,使用set-o noglob:

对于csh,使用set noglob:


我想指出另一种关闭通配符扩展的方法。您可以告诉shell使用noglob选项停止扩展通配符

对于bash,使用set-o noglob:

对于csh,使用set noglob:


但是我可以说ls-R*.txt没有单引号,并且可以得到一个递归列表。这是怎么回事?是的,我知道-R和-R是表示递归下降的常用选择。我故意用另一封信来避免得到太具体的问题答案。不,你没有。将-R选项与“ls”和通配符组合在一起并不会给出与该模式匹配的所有文件的递归列表。@安德鲁:是的,也不是……你是对的;如果没有目录名“*.txt”,则不会得到递归列表。如果有一个名为xyz.txt的目录,那么您就错了。但基本上你是对的ls-R*.txt'不会将列出的文件限制为以“.txt”结尾的名称。@AdrianMcCarthy-ls-R*.txt可以工作,因为-R选项适用于整个ls命令。因此,shell展开通配符,然后ls递归地列出所有参数。试着运行ls-R dir1.txt dir2.txt或任何合适的名称来查看它。但是我可以说ls-R*.txt没有单引号,并得到一个递归列表。这是怎么回事?是的,我知道-R和-R是表示递归下降的常用选择。我故意用另一封信来避免得到太具体的问题答案。不,你没有。将-R选项与“ls”和通配符组合在一起并不会给出与该模式匹配的所有文件的递归列表。@安德鲁:是的,也不是……你是对的;如果没有目录名“*.txt”,则不会得到递归列表。如果有一个名为xyz.txt的目录,那么您就错了。但基本上你是对的ls-R*.txt'不会将列出的文件限制为以“.txt”结尾的名称。@AdrianMcCarthy-ls-R*.txt可以工作,因为-R选项适用于整个ls命令。因此,shell展开通配符,然后ls递归地列出所有参数。尝试运行ls-R dir1.txt dir2.txt或其他合适的名称,以查看名为globs的.BTW-shell通配符以及名为globs的glob3.BTW-shell通配符可通过编程方式获得的功能。该功能可通过使用glob3通过编程方式获得。这对我来说似乎不准确-我可以运行命令类似于查找src-name*.orig并返回与我引用上一个参数时相同的结果。但这是在OS X上。@gsteff:如果当前工作目录中有.orig文件,则这将不起作用。如果且仅当没有任何匹配项时,shell可能会保留*.orig,如果未设置nullglob shell选项,bash就会这样做。echo是一个很好的p
这对我来说似乎并不准确——我可以运行find src-name*.orig这样的命令,得到与引用上一个参数时相同的结果。但这是在OS X上。@gsteff:如果当前工作目录中有.orig文件,则这将不起作用。如果且仅当没有任何匹配项时,shell可能会保留*.orig,如果未设置nullglob shell选项,bash就会这样做。echo是一个测试这些东西的好程序。