2

I'm retrying to replace all of the copyright headers in my project (100+ files) with a new version. Currently I have something like this at the start of each file:

<?php
/**
 * Project name
 *
 * @copyright Apache 2.0
 * @author    FooBar
 */

And I want all my files to start like this:

<?php
/**
 * Copyright 2014 FooBar
 *
 * 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.
 */

I've already looked at:

  • this thread, which I can't get working. It does a partial replacement, keeping certain lines of the original text in the new text. I want a complete replacement.

  • this script, which similarly doesn't work for my use case. It replaces the very start of each file with a new header, which causes the existing content (<?php /** */) to be appended to the new comment, thereby causing parse errors.

Does anybody know how I can do a recursive multi-line file replace? Do I need to use sed/awk?

SOLUTION:

I just need to execute this bash script:

INPUT=../path

find $INPUT -name "*.php" -exec sed -i -e '2,/\*\//d; 1r copyright.txt' {} \;
Community
  • 1
  • 1
hohner
  • 11,498
  • 8
  • 49
  • 84

4 Answers4

4

Is it safe to assume all your files start with

<?php
/**

If so, you can use

sed '2,/\*\//d; 1r newSig.txt' input.txt

The first command deletes the signature from line 2 til the end of the signature. You could use a dynamic range but it would also delete other multi-line signatures in the file. The second command reads the file newSig.txt, which has your new signature, and appends it after line 1.

pfnuesel
  • 14,093
  • 14
  • 58
  • 71
3

With GNU awk for a multi-char RS to read the whole file as a single string:

$ gawk -v RS='^$' -v hdr="\
/**
 * Copyright 2014 FooBar
 *
 * Licensed under the blah blah blah
 */\
" '{sub(/\/\*[^/]+\*\//,hdr)}1' file
<?php
/**
 * Copyright 2014 FooBar
 *
 * Licensed under the blah blah blah
 */
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
2

NOTE: you should read Ed Morton's comment too. Regarding that is a problem, you can check the files and only pass the readable ones in you for cycle before running the awk script.

If your files always start like this, one way to solve it with gawk is

awk 'FNR==1 { print $0
              print "INSERT YOUR new header here even on multiline print statements." 
              # if you don't mind your old header, stop here and skip the below rules
            }
     FNR==2 && $0 ~ "/\*\*" { 
              while (getline) {
                if ($0 == "*/") { getline ; break }
              }
            }
     FNR>2  { print $0 }' INPUTFILE

And you can wrap it in for cycle, like

for file in *php ; do
    awk ... $file > $file.new
done
Community
  • 1
  • 1
Zsolt Botykai
  • 50,406
  • 14
  • 85
  • 110
  • 1
    That will go into an infinite loop first time it encounters a file it can't open. If you're considering using `getline`, make sure you read http://awk.info/?tip/getline and fully understand all of the caveats and appropriate applications (of which this isn't one). – Ed Morton Feb 11 '14 at 12:51
  • 1
    You are right as always @EdMorton, I'm editing the post. – Zsolt Botykai Feb 11 '14 at 12:56
1

My way is no limit on fix line of

<?php
/**

it will replace the first pair of /** to next **/

1) Save the replace content into file: update.txt (not set suffix to php)

2) then run this command on one php file (abc.php) to confirm first

sed ':a;$!{N;ba};s!/[^/]*/!########!1' abc.php|sed -e '/########/{r update.txt' -e 'd}'

3) if it is fine, then run the script on all php files:

for file in *.php
do
  sed ':a;$!{N;ba};s!/[^/]*/!########!1' $file|sed -e '/########/{r update.txt' -e 'd}' > temp
  mv temp "$file"
done
BMW
  • 42,880
  • 12
  • 99
  • 116