Is there a way to filter a text file using grep (or any other tool) so that you can get a section of the file that is cuffed or braced?

I ended up with several files that look something like this:

universe = {
    ["stars"] = {
        ["Sun"] = {
            ["planets"] = "9",
            ["life"] = "Yes",
            ["asteroid"] = "9001"
        },
        ["Alpha Centauri"] = {
            ["planets"] = "3",
            ["life"] = "No",
            ["asteroid"] = "20"
        },
        ["Rigel"] = {
            ["planets"] = "5",
            ["life"] = "No",
            ["asteroid"] = "11"
        }
    }
}

      

My intention is to find, for example, every block where ["life"] equals "No". I understand this could be handled better if it was in the database (or something with a structure), but I'm not sure how to convert this data to this.

I have a bunch of files in this format and I would like to run a command that could display the sections (up to the immediate parent bracket) where the condition is true, so for the previous example I would like to get:

        ["Alpha Centauri"] = {
            ["planets"] = "3",
            ["life"] = "No",
            ["asteroid"] = "20"
        },
        ["Rigel"] = {
            ["planets"] = "5",
            ["life"] = "No",
            ["asteroid"] = "11"
        }

      

Can this be done with GREP? Or is there another tool that could do something like this?

Any help is appreciated. Thanks in advance.

EDIT

Example 2: https://regex101.com/r/jO9dU5/1

+3


source to share


4 answers


Yes, it is possible via grep which supports the -P

(Perl Regex) option .

$ grep -oPz '.*\[[^\[\]]*\]\s*=\s*\{[^{}]*\["life"\]\s*=\s*"No"[^{}]*}.*' file
        ["Alpha Centauri"] = {
            ["planets"] = "3",
            ["life"] = "No",
            ["asteroid"] = "20"
        },
        ["Rigel"] = {
            ["planets"] = "5",
            ["life"] = "No",
            ["asteroid"] = "11"
        }

      

DEMO

From grep --help

 -z, --null-data           a data line ends in 0 byte, not newline
 -o, --only-matching       show only the part of a line matching PATTERN

      



Update:

\[[^\n]*\]\h*=\h*\{(?!,\s*\[[^\[\]]*\]\h*=\h*{).*?\["fontSize"\]\h*=\h*20,.*?\}(?=,\s*\[[^\[\]]*\]\h*=\h*{|\s*})

      

DEMO

$ pcregrep -oM '(?s)[^\n]*\[[^\n]*\]\h*=\h*\{(?!,\s*\[[^\[\]]*\]\h*=\h*{).*?\["fontSize"\]\h*=\h*20,.*?\}(?=,\s*\[[^\[\]]*\]\h*=\h*{|\s*})' file
    ["frame 1"] = {
        ["fontSize"] = 20,
        ["displayStacks"] = "%p",
        ["xOffset"] = 251.000518798828,
        ["stacksPoint"] = "BOTTOM",
        ["regionType"] = "icon",
        ["yOffset"] = 416.000183105469,
        ["anchorPoint"] = "CENTER",
        ["parent"] = "Target Shit",
        ["numTriggers"] = 1,
        ["customTextUpdate"] = "update",
        ["id"] = "Invulnerabilities 2",
        ["icon"] = true,
        ["fontFlags"] = "OUTLINE",
        ["stacksContainment"] = "OUTSIDE",
        ["zoom"] = 0,
        ["auto"] = true,
        ["selfPoint"] = "CENTER",
        ["width"] = 60,
        ["frameStrata"] = 1,
        ["desaturate"] = false,
        ["stickyDuration"] = true,
        ["font"] = "Emblem",
        ["inverse"] = false,
        ["height"] = 60,
    }
    ["frame 2"] = {
        ["fontSize"] = 20,
        ["displayStacks"] = "%p",
        ["parent"] = "Target Shit",
        ["xOffset"] = 118.000427246094,
        ["stacksPoint"] = "BOTTOM",
        ["anchorPoint"] = "CENTER",
        ["untrigger"] = {
        },
        ["regionType"] = "icon",
        ["color"] = {
            1, -- [1]
            1, -- [2]
            1, -- [3]
            1, -- [4]
        },
        ["desaturate"] = false,
        ["frameStrata"] = 1,
        ["stickyDuration"] = true,
        ["width"] = 60,
        ["font"] = "Emblem",
        ["inverse"] = false,
        ["icon"] = true,
        ["height"] = 60,
        ["yOffset"] = 241
    }

      

(?s)

The DOTALL modifier, which makes dots in your regex equal line breaks.

+1


source


Try this Lua program:

local function find(w,t,p)
    for k,v in pairs(t) do
        if v==w then
            print(p.."."..k)
        elseif type(v)=="table" then
            find(w,v,p.."."..k)
        end
    end
end

find("No",universe,"universe")

      

Add a definition universe

before this code.



If you really want to process the text, try this instead:

S=[[
universe = {
...
}
]]

for w in S:gmatch('%b[] = {[^{]-"No".-},?') do
    print(w)
end

      

+2


source


Using the correct parser in

This is not a quick dirty snippet, but a reliable way to query lua DS:

use strict; use warnings;
use Data::Lua;                              # lua 2 perl parser
use Data::Dumper;                           # to dump Data Structures (in color)

# retrieving the lua'DS in a perl DS
my $root = Data::Lua->parse_file('lua.conf');

# iterating over keys of planet HASH
foreach my $planet (keys $root->{universe}->{stars}) {
    print Dumper { $planet => $root->{universe}->{stars}->{$planet} }
        if $root->{universe}->{stars}->{$planet}->{life} eq "No";
}

      

Output

$VAR1 = {
     'Rigel' => {
            'planets' => '5',
            'life' => 'No',
            'asteroid' => '11'
           }
    };
$VAR1 = {
     'Alpha Centauri' => {
                'asteroid' => '20',
                'life' => 'No',
                'planets' => '3'
               }
    };

      

how

  • install Data::Lua

    if not already installed with# cpan Data::Lua

  • put the data structure in a file lua.conf

  • put this script in the same directory in the example lua_DS_parser.pl

  • run your script with $ perl lua_DS_parser.pl

  • enjoy;)
+1


source


You can use something like this
  grep -C 2 -E 'life. + = "No" 'path_to_file

But in my opinion, the best way is to convert the files to some common format.

0


source







All Articles