如何使用sed替换源文件中的版权/许可证头?

时间:2013-01-01 01:39:52

标签: macos unix command-line sed licensing

我需要使用Apache License 2.0标头替换所有Java源文件中的LGPL许可证标头,即

/*
 * Copyright (c) 2012 Tyler Treat
 * 
 * This file is part of Project Foo.
 *
 * Project Foo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Project Foo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Project Foo.  If not, see <http://www.gnu.org/licenses/>.
 */

需要成为

/*
 * Copyright (c) 2012 Tyler Treat
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

我认为最简单的方法是使用sed对所有出现的版权标题进行查找和替换。我是一个Unix新手,所以我遇到问题,让命令按照我需要的方式工作 - 特别是处理多行字符串。基本上,如下所示,除了代替foobar的相应标题:

find . -name "*.java" -print | xargs sed -i 's/foo/bar/g'

据我所知,sed一次只能在一行上运行,所以也许总有一个更好的解决方案?

3 个答案:

答案 0 :(得分:12)

find . -name "*.java" -print0 | xargs -0 \
sed -i -e '/Project Foo is free software/,/along with Project Foo/c\
 * Licensed under the Apache License, Version 2.0 (the "License");\
 * you may not use this file except in compliance with the License.\
 * You may obtain a copy of the License at\
 *\
 *  http://www.apache.org/licenses/LICENSE-2.0\
 *\
 * Unless required by applicable law or agreed to in writing, software\
 * distributed under the License is distributed on an "AS IS" BASIS,\
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
 * See the License for the specific language governing permissions and\
 * limitations under the License.'

c命令将行范围更改为指定的文本。该范围由包含'Project Foo is free software'的行标识,直到包含'with Project Foo'的行。 -i的{​​{1}}选项表示GNU sed;因此,我假设你也有GNU sedfind,并使用xargs-print0来避免文件名中的空白等问题。

为此,我可能想把-0脚本放到一个文件(sed)中,然后可以用它:

sed.script

我觉得这更整洁,但美丽是旁观者的眼睛。


  

只有一个问题:星号上的对齐有点偏差,是否需要使用某种空白字符来缩进它们?我尝试在替换字符串中添加空格,但这似乎没有效果。

Grrr ......这是我无法做到的那种烦恼(你也是)。似乎“更改”数据行的前导空白被find . -name "*.java" -exec sed -i -f sed.script {} + 删除。它似乎是sed而不是sed;我使用bash获得了相同的结果,并且在命令行上也使用了脚本文件而不是ksh选项。 <\ n>输出时,您无法编辑“更改”数据。

一种可行的技巧 - 但你可能不会热衷于它:

-e

$ cat sed.script /Project Foo is free software/,/along with Project Foo/c\ * Licensed under the Apache License, Version 2.0 (the "License");\ * you may not use this file except in compliance with the License.\ * You may obtain a copy of the License at\ *\ * http://www.apache.org/licenses/LICENSE-2.0\ *\ * Unless required by applicable law or agreed to in writing, software\ * distributed under the License is distributed on an "AS IS" BASIS,\ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\ * See the License for the specific language governing permissions and\ * limitations under the License. $ s2p -f sed.script > perl.script $ find . -name "*.java" -exec perl -f perl.script -i.bak {} + $ 程序是Perl发行版的标准部分,它将s2p脚本转换为Perl脚本,但它保留了替代数据中的前导空格。我不是很喜欢这个,但我能想到的唯一选择就是在每个文件中进行两次传递。替换数据可能是:

sed

在完成主文本替换后,您可以执行以下操作:

$ cat sed.script
/Project Foo is free software/,/along with Project Foo/c\
@*@ Licensed under the Apache License, Version 2.0 (the "License");\
@*@ you may not use this file except in compliance with the License.\
@*@ You may obtain a copy of the License at\
@*@\
@*@  http://www.apache.org/licenses/LICENSE-2.0\
@*@\
@*@ Unless required by applicable law or agreed to in writing, software\
@*@ distributed under the License is distributed on an "AS IS" BASIS,\
@*@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\
@*@ See the License for the specific language governing permissions and\
@*@ limitations under the License.
$

这会跟踪从$ find . -name "*.java" -exec sed -i 's/^@\*@/ */' {} + $ 开始的行,并用“@*@”(空白星号)替换该文本。不是那么干净整洁,但我不会经常这样做,我相信。

答案 1 :(得分:5)

使用GNU Sed替换部分许可

您可以使用GNU sed通过一些正则表达式行匹配和读取表达式来解决此问题。以下是步骤。

使用文件保存替换文本

首先,创建一个文件来保存许可证的替换部分:

cat << EOF > /tmp/license
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
EOF

运行实际Sed调用

接下来,运行 find 来收集文件列表,并调用以下sed脚本进行更改:

find . -name '*.java' |
xargs sed -i'' '/Copyright.*Tyler Treat/,/\*\// {
                    /Copyright/n
                    /\*\//r /tmp/license
                    d
                }'

兼容性说明

此解决方案可能适用于或不适用于其他版本的sed,但已在本地进行测试,并且已知可与GNU sed版本4.2.1一起使用。如果它不适用于您的OS X版本附带的sed版本,则可以通过MacPorts或类似版本安装GNU sed。

答案 2 :(得分:2)

假设file1包含您的原始文本,而file2包含您的替换版权注释:

awk 'f; /\*\//{system("cat file2");f=1}' file1

上面只是查找原始文件中的第一个结束注释行,当它找到cat替换文件并打开原始文件的剩余部分时打印。