【问题标题】:Make changes in multiple files using sed and find使用 sed 和 find 在多个文件中进行更改
【发布时间】:2015-09-26 20:38:31
【问题描述】:

我必须浏览 100 多个站点并将两行添加到所有站点的同一个文件 (sendmail1.php)。 老板想让我手动复制/粘贴这些东西,但肯定有更简单的方法,所以我尝试用 find 和 sed 来做,这两个显然我都没有很好地使用。我只想在包含所有站点的目录的目录中运行一个脚本。

我有这个:

#!/bin/bash

read -p "Which file, sir? : " file

# find . -depth 1  -type f -name 'sendmail1.php' -exec \


sed -i 's/require\ dirname\(__FILE__\).\'\/includes\/validate.php\';/ \
        a require_once dirname\(__FILE__\).\'\/includes\/carriersoft_email.php\';' $file


sed -i 's/\else\ if\($_POST[\'email\']\ \&\&\ \($_POST\'work_email\'\]\ ==\ \"\"\)\){/ \
        a\t$carriersoft_sent = carriersoft_email\(\);' $file

exit 0

目前,我在尝试在这里整理 sed 并测试脚本时将 find 注释掉了,但我想同时解决这两个问题。 我想我并没有在 sed 位中逃避一些必要的事情,但我一直在检查它并对其进行更改并得到不同的错误(有时是“未完成的 s/ 语句”,其他时候。其他东西。

关键是我必须这样做:

require dirname(__FILE__).'/includes/validate.php';的正下方,添加这一行:

require_once dirname(__FILE__).'/includes/carriersoft_email.php';

else if($_POST['email'] && ($_POST['work_email'] == "")){ 下,添加这一行:

$carriersoft_sent = carriersoft_email();

我想把这个 4 小时的复制/意大利面噩梦变成一个 2 分钟的懒惰管理类型脚本并完成它。 但是我的 fu 对 sed 或 find 不强... 至于查找,我得到“路径必须先于表达式:1” 我在这里找到了解决该错误的问题,但表明使用 '' 包围文件名应该可以解决它,但它不起作用。

【问题讨论】:

  • "(...) 将两行添加到所有文件中的同一个文件中 (...)" — 那么只更改一个文件并将其复制到所有其他文件不是更容易吗地点?
  • 文件的其他部分可能存在其他特定于站点的差异。当我问到“为什么不直接将编辑后的文件复制到所有这些位置?”时,我无法让老板澄清这一点。虽然我vimdiff了一些,但找不到任何区别。
  • 好的。我确实收到了老板的回复:“我更愿意编辑每个文件,我不确定我们可能为其他特定网站所做的自定义。”
  • 好的,但仅供参考:检查所有此类文件是否相同很容易 - 只需选择其中一个并将其与所有其他文件进行比较:find . -name 'sendmail1.php' -exec diff -q path/to/reference/senmail1.php {} \;(将 path/to/reference/senmail1.php 替换为所选文件文件)。 diff 命令仅在文件不同时才会输出任何内容。如果它们与单个选择的文件相同,则它们都是相同的。 :)
  • 谢谢。那肯定会派上用场。这些家伙按小时给我发工资,并为这份工作预算了 5 小时,所以我可以按时完成,但我宁愿用效率让他们眼花缭乱。

标签: regex bash sed find


【解决方案1】:

保持简单,只使用 awk,因为 awk 可以对字符串进行操作,不像 sed,它只适用于带有额外警告的 RE:

find whatever |
while IFS= read -r file
do
    awk '
        { print }
        index($0,"require dirname(__FILE__).\047/includes/validate.php\047;") {
            print "require_once dirname(__FILE__).\047/includes/carriersoft_email.php\047;"
        }
        index($0,"else if($_POST[\047email\047] && ($_POST[\04work_email\047] == "")){") {
            print "$carriersoft_sent = carriersoft_email();"
        }
    ' "$file" > /usr/tmp/tmp_$$ &&
    mv /usr/tmp/tmp_$$ "$file"
done

使用 GNU awk,您可以使用 -i inplace 来避免手动指定 tmp 文件名,就像使用 sed -i 一样。

\047s 是在单引号分隔的脚本中指定单引号的一种方式。

【讨论】:

    【解决方案2】:

    试试这个:

    sed -e "s/require dirname(__FILE__).'\/includes\/validate.php';/&\nrequire_once dirname(__FILE__).'\/includes\/carriersoft_email.php'\;/" \
    -e "s/else if(\$_POST\['email'\] && (\$_POST\['work_email'\] == \"\")){/&\n\$carriersoft_sent = carriersoft_email();/"                   \
    file
    

    注意:我没有使用-i 标志。一旦你确认它对你有用,你就可以使用-i 标志。此外,我已将您的两个 sed 命令与 -e 选项合并为一个。

    【讨论】:

      【解决方案3】:

      我认为如果你使用另一个很好的命令a 而不是s 会更清楚。要输出一个更改的文件,请创建一个包含以下内容的脚本(例如script.sed):

      /require dirname(__FILE__)\.'\/includes\/validate.php';/a\
      require_once dirname(__FILE__).'/includes/carriersoft_email.php';
      /else if(\$_POST\['email'\] && (\$_POST\['work_email'\] == "")){/a\
      $carriersoft_sent = carriersoft_email();
      

      然后运行sed -f script.sed sendmail1.php

      要在所有文件中应用更改,请运行:

      find . -name 'sendmail1.php' -exec sed -i -f script.sed {} \;
      

      -i 导致 sed 就地更改文件)。

      在此类操作中始终建议进行备份并在运行命令后检查确切的更改。 :)

      【讨论】:

      • 使用sed -i.bak … 自动备份文件。当然,这些文件也应该在配置管理(版本控制)下,并进行备份,因此不应该有任何长期风险,但将风险和可能的时间降至最低很重要-out 如果编辑在实时系统上。而且您需要一个恢复计划——能够重命名所有 .bak 文件而不使用它们的后缀。
      • 另外,只有开方括号必须在第二种模式中转义。
      猜你喜欢
      • 2015-01-22
      • 2011-10-09
      • 2020-07-04
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 2016-11-09
      相关资源
      最近更新 更多