在众多 HTML 文件中查找和替换字符串的最快方法

Ben*_*Ben 3 command-line editors text-processing

我有许多 HTML 文件,它们都嵌套在包含在单个整体文件夹中的不同文件夹中。在我需要替换的每个 HTML 文件中

/contact/index.html
Run Code Online (Sandbox Code Playgroud)

和

/contact/index.php
Run Code Online (Sandbox Code Playgroud)

有没有从命令行执行此操作的简单方法?

ter*_*don 5

是的,如果您有 GNUfind和 GNU sed,请在父文件夹中尝试:

find . -type f \( -iname "*.htm" -o -iname "*.html" \) -exec sed -i.bak 's#/contact/index\.html#/contact/index.php#' '{}' +
Run Code Online (Sandbox Code Playgroud)

这将找到名称以.htmlor .HTMLor .htmor .HTM(or .HtM...)结尾的所有文件,sed并对它们运行以下命令:

sed -i.bak 's#/contact/index\.html#/contact/index.php#g'
Run Code Online (Sandbox Code Playgroud)

这将进行您想要的替换并创建一个foo.htm名为foo.htm.bak. 如果您不想要备份,只需删除.bak.


细节:

find显然,该命令查找文件或文件夹。它的语法可能非常复杂,并在其man page部分内容中进行了详细解释,如下所示:

一般格式为find [where] [what]. 在我上面给出的示例中,whereis.表示当前目录。这what是所有具有html或类似扩展名的文件,所以我使用的iname是:

   -iname pattern
          Like -name, but the match is case insensitive.
          For example,  the  patterns  `fo*'  and  `F??'
          match  the  file  names  `Foo',  `FOO', `foo',
          `fOo', etc.   
Run Code Online (Sandbox Code Playgroud)

但是,我希望它同时匹配两者html,htm因此我使用了-o标志,这意味着:

  expr1 -o expr2
          Or; expr2 is not evaluated if expr1 is true.
Run Code Online (Sandbox Code Playgroud)

这样的结构需要组合在一起,这是通过括号完成的( ),但是,需要从 shell 中转义,所以我们使用\(and \)。

神奇发生在以下-exec部分:

   -exec command ;
          Execute command; true if 0 status is returned.
          All following arguments to find are  taken  to
          be  arguments to the command until an argument
          consisting of `;' is encountered.  The  string
          `{}'  is  replaced  by  the  current file name
          being processed everywhere it  occurs  in  the
          arguments  to  the  command, not just in argu?
          ments where it is alone, as in  some  versions
          of  find.   [...] The specified command is
          run once for each matched file.   The  command
          is executed in the starting directory.   There
          are unavoidable security problems  surrounding
          use  of  the  -exec action; you should use the
          -execdir option instead.
Run Code Online (Sandbox Code Playgroud)

换句话说,给定一个命令,如-exec ls {},find将找到所有与您设置的条件匹配的文件并遍历它们,替换{}为当前文件名并执行给定的命令。我还使用+而不是\;结束exec呼叫,因为这将导致find尝试运行尽可能少的命令,这只是一个次要的优化,除非您有数千个文件可能很重要:

   -exec command {} +
          This variant of  the  -exec  action  runs  the
          specified  command  on the selected files, but
          the command line is built  by  appending  each
          selected  file name at the end; the total num?
          ber of invocations of the command will be much
          less  than  the  number of matched files.  The
          command line is built in  much  the  same  way
          that xargs builds its command lines.  Only one
          instance of `{}' is allowed  within  the  com?
          mand.  The command is executed in the starting
          directory.
Run Code Online (Sandbox Code Playgroud)

最后,sed是一个命令行文本流编辑器,它将您给它的命令应用到文件的每一行。在这种情况下,命令是一个替换,基本格式为:

s#pattern#replacement#flags
Run Code Online (Sandbox Code Playgroud)

分隔符 ( #) 可以是任何特殊字符,传统上是这样,/但我选择了#,否则我将不得不转义/. 请注意,ChrisDown 在他的回答中选择使用|. 这只是个人选择,两者是等效的。