3

我正在尝试在目录(Linux)中的所有源文件中更新或插入一些评论,例如版权标头。我的文件不一致,因此其中一些文件已经有标题,而其他文件则根本没有。我尝试sed查看前几行并替换。替换我的意思是将已经具有版权标题的文件更改为最新的文件。

sed -e '1,10 s/Copyright/*Copyright*/g' file

但是,如果它没有找到模式,这将不会插入。我怎样才能做到这一点?

我在评论中提供的示例或我试图实际替换/插入的是多行典型版权标题,如下所示

/*
* Copyright 1234 XXXNAME, XYZPlace 
*  text text text text ...........
* blah blah blah */

它也可能包含一些特殊字符。

4

3 回答 3

9

如果我理解正确,您想要:

  • 查找前 10 行中没有版权声明的文件,以及
  • 为这些文件添加版权声明。

此外,您还希望:

  • 在前 10 行中查找带有版权声明的文件,以及
  • 将他们的通知更新为您的标准文本。

在我看来,这两个任务可以归结为一组:

  • 删除前 10 行中的任何现有版权声明,然后
  • 在文件中插入新的版权声明。

如果我们可以安全地假设您在问题的评论中输入的示例文本的缩短版本是有效的,并且应该插入例如每个文件的第 2 行,那么以下内容应该满足第一组要求,如果您正在使用 GNU sed:

find . -type f -not -exec grep -q Copyright {} \; -exec sed -i'' '2i/* Copyright */' {} \;

如果您没有运行 GNU sed(即您使用的是 FreeBSD、OSX 或 Solaris 等),请告诉我们,因为 sed 脚本会有所不同。

这是如何工作的

find命令正在获取以下选项:

  • -type f告诉它只查看文件(而不是目录或设备)。
  • -not反转以下选项。
  • -exec grep -q Copyright {} \;将搜索限制为包含版权的任何内容(由 修改-not
  • -exec sed -i'' '2i/* Copyright */' {} \;插入您的版权声明。

如果您希望您的版权声明包含将由 sed 脚本解释的特殊字符,此解决方案可能会遇到困难。但它回答了你的问题。:)

相反,如果我们想处理修改后的要求,即首先删除现有的版权声明,那么我们可以使用两个单行代码来完成:

首先,我们删除现有的版权声明。

find . -type f -exec sh -c 'head {} | grep -q Copyright' \; -exec sed -ne '10,$ta;/Copyright/d;:a;p' {} \;

这可能有点多余,除非您想递归地遍历子目录,find默认情况下这样做。sed 脚本对前 10 行中没有版权信息的文件不执行任何操作,因此如果您的所有文件都在一个目录中,则以下内容也应该起作用:

for file in *;do sed -ne '10,$ta;/Copyright/d;:a;p' "$file"; done

接下来,我们重新添加新的。

for file in *;do sed -i'' '2i/* Copyright */' "$file"; done

或者,如果您想通过子目录递归地执行此操作:

find . -type f -exec sed -i'' '2i/* Copyright */' {} \;

最后更新

在这之后我不能再花更多时间在这上面了。

find . -type f \
  -exec sh -c 'head {} | grep -q Copyright' \; \
  -exec sed -ne '1h;1!H;${;g;s:/\*.*Copyright.*\*/:/* Copyright 1998-2012 */' {} \;

什么

第一个-exec在文件的前 10 行中搜索“版权”一词。就像我在上面发布的第一个示例一样。如果 grep 找到任何东西,则此条件返回 true。

第二个-exec是替换。它将整个文件读入 sed 的保持缓冲区。然后,当它到达文件末尾时,它 ( g) 考虑保持缓冲区,并且 ( s) 执行多行替换。

请注意,这很可能需要一些调整,如果您在文件的其他地方有注释,它可能根本不起作用。我不记得 GNU sed 是否支持非贪婪星。你可以自己研究一下。

这是我的测试:

$ printf 'one\n/* Copyright blah blah\n *\n */\ntwo\n' | sed -n '1h;1!H;${;g;s:/\*.*Copyright.*\*/:/* Copyright 1998-2012 */:g;p;}'
one
/* Copyright 1998-2012 */
two

不会维护您现有的版权信息,但至少它解决了多行问题。

于 2012-07-19T15:53:13.377 回答
0

编辑:如果您的文件名带有空格,则以下命令将不起作用,请参阅第一条评论。

它肯定可以sed只做,但我想到的第一件事是对存在该行的文件进行替换,然后使用类似的东西将标题添加到其余文件中

for f in $(grep -lv 'Copyright' *); do sed -i '1i *Copyright*' $f; done

这将适用于当前文件夹中的所有文件,如果需要递归,请使用该-r选项。grep

PS我建议删除-i sed测试选项并仅在您确定命令正常工作时添加它。

于 2012-07-19T15:12:52.737 回答
0

要在文件的第 1 行插入包含文本copyright的单行(仅当它不存在时),您可以执行以下操作:

sed '1{ /copyright/!i\
copyright
}' input-file

要插入多行:

sed '1{ /copyright/!i\
copyright\
second line
}' input-file

使用从文件中读取版权很诱人r,但我不知道如何在第 1 行之前而不是在第 1 行之后插入它。例如:

sed '1{ /copyright/! { x; r copyright-file
G}}' input-file

似乎它应该可以解决问题,但是版权文件中的文本从第 2 行开始。

于 2012-07-19T15:26:59.580 回答