gzip所有带有特定扩展名的文件


11

我正在尝试对ubuntu上所有扩展名为.css,.html或.js的文件进行gzip压缩。在顶层目录和所有子目录中。我想保留原始文件并覆盖.gz文件(如果已存在)。

因此,当我有n个文件时,我想保留这n个文件并创建其他n个存档文件。不只是一个。

我的尝试是运行一个如下所示的脚本:

gzip -rkf *.css
gzip -rkf *.html
... one line for each file extension

第一:对于要gzip压缩的每个文件扩展名,我需要在脚本中包含一行。可以,但我希望找到更好的方法

第二点,也是更重要的一点:它不起作用。尽管-r应该可以完成工作,但是子目录是不变的。gzip文件仅在顶层目录中创建。

我在这里想念什么?

顺便说一句:以下是详细输出中的错误,对吗?使用-k和-v选项时

-k, --keep        keep (don't delete) input files
-v, --verbose     verbose mode

详细输出说它将替换文件,尽管“替换”表示替换后原始文件不存在。无论如何,这仅仅是输出。

$ ls
  index.html      subdir1  testfile      testfile.css.gz
  javaclass.java  subdir2  testfile.css
$ gzip -fkv *.css
  testfile.css:   6.6% -- replaced with testfile.css.gz
$ ls
  index.html      subdir1  testfile      testfile.css.gz
  javaclass.java  subdir2  testfile.css

1
-r按设计工作。来自man gzip递归地移动目录结构。如果在命令行上指定的任何文件名是directory,则gzip将下降到该目录并压缩在该目录中找到的所有文件(如果是gunzip,则将其解压缩)。(重点是我的)
丹尼斯

好。因此,-r将输入名称为XYZ.css的目录。然后,递归没有按照我的预期进行设计。
Sadik

Answers:


7

您可以使用for循环来查找每个文件,然后对其进行压缩:

for i in `find | grep -E "\.css$|\.html$"`; do gzip "$i" ; done

谢谢!尽管该-r选项不起作用,-k并且-f正在起作用,所以我可以这样使用它们:for i in find | grep -E "\.css$|\.html$"; 做gzip -vkf“ $ i”; 完成`
Sadik

@Sadik:小心点!如果任何文件名包含空格,则此方法将不起作用。
丹尼斯

你能解释为什么不吗?
Sadik

1
@Sadik:`...`提供一个字符串,而不是列表。for使用内部字段分隔符($IFS)决定应在何处拆分该字符串。默认情况下,在分割换行,空格和制表符,所以如果你有一个名为new style.css,命令gzip newgzip style.css将被执行。
丹尼斯

1
@ Sadik,Dennis是正确的,因为快速的解决方法可以export IFS=$'\n'for循环之前运行。
mndo 2014年

14

我会用

find /path/to/dir \( -name '*.css' -o -name '*.html' \) -exec gzip --verbose --keep {} \;

如果要以不区分大小写的方式匹配扩展名(例如,包含和/或扩展名),请更改name为。如果要从当前目录开始递归搜索,则可以省略。iname.CSS.HTML/path/to/dir


2
对于那些可能会对--keep切换感到疑惑的人,是的,它可以保留原始文件。如果您希望它们一旦压缩就被删除,则忽略它。
本·约翰逊

4

要获取文件列表:

find -type f | grep -P '\.js|\.html|\.css'

并gzip所有这些文件:

find -type f | grep -P '\.js|\.html|\.css' | tar cvzf archive.gz -T -

这是不是tar列表 文件作为输出的find,而不是文件本身?
2014年

我编辑了我的问题,以明确说明我想为每个css,html或js文件创建一个存档文件。
Sadik

2
-T选项的@Jos no tar将输入作为文件名处理。
2014年

@chaos啊,谢谢。我今天学到了一些东西。
2014年

2

我使用了steeldriver的答案,但是我喜欢使用--best--force选项来完成它。

cd放入任何文件夹,然后键入此代码。您所有匹配的文件都会被压缩。

find . \( -name '*.css' -o -name '*.js' \) -exec gzip --verbose --keep --best --force {} \;
  • 用于--best获得最佳压缩率。
  • 使用--force了不问是否已经有一个gzip压缩的文件覆盖。

1

您可以使用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})

如果要不区分大小写地匹配文件名,以便包括具有全部或全部大写字母的扩展名,则还可以启用nocaseglobshell选项:

(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}包括与启动文件.,同时还不能在这做的文件夹进行搜索。

如果要同时包含名称以开头的文件和名称以开头的.目录中的文件.,则有一种更简洁的方法:启用dotglobshell选项。

(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命令,因为这是默认设置-不会产生可以安全地通过管道传输或以其他方式提供给对文件执行操作的其他命令的输出。-print0find-print-print

动作find产生的输出-print0可以安全地传递到管道xargs -0(该-0标志指示xargs期望以空分隔的输入)。


0

递归压缩文件夹/子文件夹中的所有文件:

gzip -r `find . -type f -name "*.html"` 

解压缩:

gunzip -r `find . -type f -name "*.gz"` 

这种基于命令替换的方法会经常中断,而且非常糟糕。问题在于包含空格或其他空格的文件名将被拆分并视为多个文件名。(这些命令是使用` `语法编写的,但是使用语法也完全可以解决问题$( )。)
Eliah Kagan
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.