Perl: how to get lines between patterns in linux

2019-09-05 15:20发布

问题:

I have a file like this

number: string(200)
issueDate: datetime
expiryDate: datetime
file_path: string(200)
filename: string(200)
description: text

I am using this in perl to get ouputlike

FIELDS="number: string(200) issueDate: datetime expiryDate: datetime file_path: string(200) filename: string(200) description: text"

This is done by this command

perl -plne '$_ = "FIELDS=\""."$_" if $. == 1; $\ = " ";$_ = "\""."$_" if eof' document.txt

Now i have the full file like this

[entity]
JOHN

[BUNDLE]
mybundle

[FIELDS]
number: string(200)
issueDate: datetime
expiryDate: datetime
file_path: string(200)
filename: string(200)
description: text

Now i want the ouput to terminal like this in separate lines

ENTITY = JOHN
BUNDLE = Mybundle
FIELDS="number: string(200) issueDate: datetime expiryDate: datetime file_path: string(200) filename: string(200) description: text"

basically the variables NAME like ENTITY, BUNDLE, it should get from the file

how can i do that

回答1:

perl -l -00pe '$q = y|\n\r[]| |d >3 && q("); s|(\S+)\s*|$1 = $q|; $_.= $q' file

output

entity = JOHN
BUNDLE = mybundle
FIELDS = "number: string(200) issueDate: datetime expiryDate: datetime file_path: string(200) filename: string(200) description: text"
  • -l chomps newline on input and add's it when using print
  • -00 reads input in paragraphs (these are terminated by two or more newlines)
  • y|\n\r[]| |d replaces newlines with spaces, deletes \r[] chars, and returns number of how many chars were altered
  • thus $q is assigned " char only when more than 3 chars were replaced (used for FIELDS entry)
  • s||| substitution takes first non spaces chars (entity,bundle,fields), and inerts = $q after them


回答2:

You can do it with awk like this:

awk '
   /^\[entity\]/  {getline e;next}
   /^\[BUNDLE\]/  {getline b;next}
   /:/            {f=f " " $0}
   /^description/ {print "entity=" e RS "BUNDLE=" b RS "FIELDS=" f;f=""}' yourfile

Explanation:

If I fiind a line starting with [entity] I grab the following line and save as "e"

If I find a line starting with [BUNDLE], I grab the following line and save as "b"

If I find a line with a colon, I append it to "f" where I save the fields (with added spaces)

If I find a line starting with "description", I print out what I have found so far and clear the fields variable "f".



回答3:

Here's a fairly readable perl-ish version of my awk answer:

perl -ne '
   $e=<> if /^\[entity\]/;      # save entity as $e from line after [entity]
   $b=<> if /^\[BUNDLE\]/;      # save bundle as $b from line after [BUNDLE]
   if(/:/){                     # if there's a colon in the line
      chomp; $f.= " " . $_;     # .. append this field to $f
   }
   print "entity = ",$e,"BUNDLE = ",$b,"FIELDS = \"$f\"\n" if /^desc/;
' yourfile