sed 在文件中替换,同时使用文件中的旧字符串和新字符串

sed 在文件中替换,同时使用文件中的旧字符串和新字符串

我想自动注释掉PHP文件中的代码块,如下所示:

原始块:

    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);

带注释的新块:

    /* For the production version, the following codelines are commented
       out
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    */

所以我打算将这些行放在两个文件中,并使用 sed 自动执行替换。然而,在网上搜索后,我只找到使用 sed 将字符串替换为文件内容sed - 用文件内容替换字符串,这意味着只有源模式或目标模式位于一个文件中,其余部分位于在线文件中。但文件中没有两者的样本。

那么,如何进行更换呢?我应该使用 sed 还是 awk?

答案1

不要尝试使用sed此方法,因为sed它不理解文字字符串(请参阅是否可以使用 sed 可靠地转义正则表达式元字符),使用这样的工具awk确实可以理解文字字符串。

使用 GNUawk进行多字符RSARGIND

$ awk -v RS='^$' -v ORS= '
    ARGIND < 3 { a[ARGIND]=$0; next }
    s = index($0,a[1]) {
        $0 = substr($0,1,s-1) a[2] substr($0,s+length(a[1]))
    }
    { print }
' old new file
this is
the winter
    /* For the production version, the following codelines are commented
       out
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    */
of our
discontent

或使用任何awk

$ awk '
    FNR == 1 { a[++argind]=$0; next }
    { a[argind] = a[argind] ORS $0 }
    END {
        $0 = a[3]
        if ( s = index($0,a[1]) ) {
            $0 = substr($0,1,s-1) a[2] substr($0,s+length(a[1]))
        }
        print
    }
' old new file
this is
the winter
    /* For the production version, the following codelines are commented
       out
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    */
of our
discontent

以上是使用这些输入文件运行的:

$ head old new file
==> old <==
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);

==> new <==
    /* For the production version, the following codelines are commented
       out
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    */

==> file <==
this is
the winter
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
of our
discontent

答案2

我建议您使用该patch实用程序来实现此目的。

diff1.使用命令创建补丁文件

假设您有两个文件,其中一个包含要替换的块:

$ cat toreplace.txt 
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);

另一个包含您要替换的块:

$ cat replacewith.txt 
    /* For the production version, the following codelines are commented
       out
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    */

您在它们之间创建上下文差异并将内容放入补丁文件中:

$ diff -c toreplace.txt replacewith.txt > patchfile
$ cat patchfile
*** toreplace.txt       2024-03-17 12:12:31.073270945 +0200
--- replacewith.txt     2024-03-17 12:12:45.276887865 +0200
***************
*** 1,4 ****
--- 1,7 ----
+     /* For the production version, the following codelines are commented
+        out
      //  Enable all errors
      ini_set('display_startup_errors', 1);
      ini_set('display_errors', 1);
      error_reporting(E_ALL);
+     */

2. 应用补丁

现在考虑这是原始文件:

$ cat myfile
line before 1
line before 2
line before 3
    //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
line after 1
line after 2 
line after 3

您可以使用之前创建的patch文件对要更改的文件运行命令。patchfile

$ patch -cb myfile patchfile
patching file myfile
Hunk #1 succeeded at 4 (offset 3 lines).
  • 旗帜-c-c“将补丁文件解释为上下文差异(指定或选项时实用程序 diff 的输出-C)。”
    • 这不是严格要求的,因为没有它patch实用程序应尝试确定差异列表的类型,除非被-c-e-n选项否决。”
  • 选项-b“在应用差异之前,将每个修改文件的原始内容的副本保存在同名的文件中,并附加后缀.orig。”
    • 如果您不想创建备份,可以删除此标志。

3. 验证

现在将原始文件与修补后的文件进行比较:

$ diff -c myfile{.orig,}
*** myfile.orig 2024-03-17 13:00:24.936142831 +0200
--- myfile      2024-03-17 13:13:48.882669202 +0200
***************
*** 1,10 ****
--- 1,13 ----
  line before 1
  line before 2
  line before 3
+     /* For the production version, the following codelines are commented
+        out
      //  Enable all errors
      ini_set('display_startup_errors', 1);
      ini_set('display_errors', 1);
      error_reporting(E_ALL);
+     */
  line after 1
  line after 2 
  line after 3

答案3

 sed -e '1s/.*/\/* For the production version, the following codelines are commented\nout\n&/g'  -e '$s/.*/&\n*\//g'filename


output

/* For the production version, the following codelines are commented
out
  //  Enable all errors
    ini_set('display_startup_errors', 1);
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
*/

相关内容