您可以使用globstar。
随着globstar
允许的shell选项,所有你需要的是gzip -vk **/*.{css,html}
。
Bash shell中有一个globstar
选项,可以让你写递归水珠用**
。shopt -s globstar
启用它。但是您可能不想对以后运行的其他命令执行此操作,因此可以gzip
在子外壳中运行它和命令。
此命令gzip
一切都.css
和.html
文件在当前目录下的任何子目录,任何其子目录等,保持原始文件(-k
),并告诉你它是做什么(-v
):
(shopt -s globstar; gzip -vk **/*.{css,html})
如果要不区分大小写地匹配文件名,以便包括具有全部或全部大写字母的扩展名,则还可以启用nocaseglob
shell选项:
(shopt -s globstar nocaseglob; gzip -vk **/*.{css,html})
;
分隔两个命令,外部命令(
)
使它们在子shell中运行。在子shell中设置shell选项不会导致在调用shell中对其进行设置。如果确实要启用,globstar
则可以运行shopt -s globstar
;然后您可以运行以下命令:
gzip -vk **/*.{css,html}
您可以禁用globstar
使用shopt -u globstar
。您可以检查是否当前启用了shopt globstar
。
怎么运行的
该gzip
命令工作方式的关键在于,shell在其上执行扩展以生成具有匹配名称的目录层次结构中每个文件的列表,然后将每个文件名作为参数传递给gzip
。
- 括号扩展轮流
**/*.{css,html}
进入**/*.css **/*.html
。
- 然后,globbing将这两种模式扩展为当前目录下可访问的文件名(
**
,由于globstar
),其文件名由任何内容(*
)后跟指定的后缀(.css
或.html
在本例中)组成。
这与名称以开头.
或位于以这种方式命名的目录中的文件不匹配。您可能没有任何这样的HTML和CSS文件,如果有,您可能不想包含它们。但是,如果您确实希望包含它们,则可以根据需要明确匹配它们。例如,改变**/*.{css,html}
到**/{,.}*.{css,html}
包括与启动文件.
,同时还不能在这做的文件夹进行搜索。
如果要同时包含名称以开头的文件和名称以开头的.
目录中的文件.
,则有一种更简洁的方法:启用dotglob
shell选项。
(shopt -s globstar dotglob; gzip -vk **/*.{css,html})
或者,如果您希望不区分大小写的匹配和以.
以下内容开头的文件名匹配:
(shopt -s globstar nocaseglob dotglob; gzip -vk **/*.{css,html})
尽管很罕见,但有可能**
扩展到太长的时间。
如果您有大量以此方式命名的文件,则此操作可能会失败,并显示一条错误消息,说明shell无法构建命令行,因为它太长了。(即使有成千上万个文件,这通常也不是问题。)
gzip
根本不会被打电话,所以您不会得到一份半完成的工作。
如果发生此错误,或者您担心该错误,可以将其find
与一起使用-exec
,如steeldriver描述(与{} \;
)或我在下文描述(与{} +
)。
您可以将find
其与-exec
动作配合使用并+
提高效率。
该gzip
命令支持为要压缩的多个文件指定名称。但是,此find
命令虽然效果很好,并且除非有很多文件,否则不会很慢,但会对每个 文件运行gzip
一次命令:
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} \;
这行得通,您绝对可以使用它。(.
从当前目录中搜索。除此之外,在steeldriver的很好回答中,这实际上是写命令的一种稍微不同的方式;您可以使用任何喜欢的样式。)
您还可以find
将多个文件名传递给gzip
它,并根据需要仅运行多次-几乎总是一次。为此,请使用+
代替\;
。该+
参数应该刚过来{}
。用其他文件名find
替换+
(如果有)。
find . \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
它的优良使用+
,即使只有几个匹配的文件,当有很多人,它可以明显快有一个单独gzip
为每个文件调用。
正如steeldriver所提到的,您可以使用-iname
而不是-name
匹配名称以大写字母开头.css
或.html
不同的文件。这对应nocaseglob
于上述globstar
基于方法的启用。
最后,您可能没有任何以开头的匹配文件或目录.
。但是,如果这样做,将find
自动包括它们。如果要排除它们(如globstar
上面dotglob
关闭时详细说明的基于-based的方法一样),可以:
find . -not -path '*/.*' \( -name \*.css -o -name \*.html \) -exec gzip -vk {} +
globstar
上面描述的基于-的方法更易于编写,尤其是当您排除以开头的目录和文件时.
,因为这是默认设置。
什么不能做?
文件名可以包含除路径分隔符/
和空字符以外的任何字符。存在许多打破奇怪文件名的技术,它们通常比总是可行的技术复杂。因此,我建议即使您知道(或认为您知道)他们也可以,在您的特定情况下也不要这样做。当然,如果您的文件名带有特殊处理的字符(包括空格),则一定不要使用它们。
如果您使用或类似的动作使它在路径之间放置一个空字符(而不是换行符),则可以安全地将其输出find
传递给另一个处理该命令的命令,否则就不会。文件名可以包含换行符(尽管我不建议您使用它们来命名文件)。具有操作的命令-包括没有显式操作的find命令,因为这是默认设置-不会产生可以安全地通过管道传输或以其他方式提供给对文件执行操作的其他命令的输出。-print0
find
-print
-print
动作find
产生的输出-print0
可以安全地传递到管道xargs -0
(该-0
标志指示xargs
期望以空分隔的输入)。
-r
按设计工作。来自man gzip:递归地移动目录结构。如果在命令行上指定的任何文件名是directory,则gzip将下降到该目录并压缩在该目录中找到的所有文件(如果是gunzip,则将其解压缩)。(重点是我的)