Home > database >  `perl -pe` match only start of file?
`perl -pe` match only start of file?

Time:12-10

I'm trying

perl -pe 's;\A(?!syntax:);syntax: glob\n\n;' .hgignore

On a file with these contents:

dist
node_modules
.vscode

The output I expect is:

syntax: glob

dist
node_modules
.vscode

With the caveat that I can run it repeatedly and it won't keep pre-pending.

I'm \A(?!syntax:) to anchor the regex to the start of the file and then (?! to say "not followed by". Looks like \A is matching the start of the line, not start of file.

How can I match only the very start of the file?

CodePudding user response:

With the -p switch the file is read line by line, to start with. So the code never sees the whole file, only one line at a time.

To "slurp" the whole file into $_ do perl -0777 -pe'...' file. That -0777 unsets the input record separator, so the "line" read by -p is really the whole file. See it in perlrun

Then the regex will run on the multiline string with the whole file.

With a multiline string one often needs the /m modifier, so that ^ and $ match beginning and end of lines inside the string, while we have \A to match the beginning of the whole string. One also often needs the /s modifier, so that . matches a newline as well.

However, it seems that for your purpose those aren't needed. Then, without the /m modifier the ^ anchor matches the beginning of the string, just like \A. But I do find \A still better as it expresses the intent clearly.

CodePudding user response:

The problem you are having is stemming from the fact that -p implies -n, which evaluates the program for each line of the file.

Your problem can be solved by only attempting the substitution on the first line of the file.

perl -pe's{^(?!syntax:)}{syntax: glob\n\n} if $. == 1' .hgignore

Alternatively, you could tell Perl the whole file is one line with -0777 or the newer -g.

perl -0777pe's{^(?!syntax:)}{syntax: glob\n\n}' .hgignore
  • Related