http://www.perlmonks.org?node_id=1010730

Tommy has asked for the wisdom of the Perl Monks concerning the following question:

dmidecode | perl -le '$o = qr/[^\n]+\n[^\n]+/; $a = join "", <STDIN>; +$a =~ s/(Socket Designation: RAM($o)Bank($o)Current($o)Type($o)Instal +led Size: \d[^\n]+\n)/print $1/smge'

There has GOT to be a better way to get the following block of text out of dmidecode...

        Socket Designation: RAM socket #0
        Bank Connections: 0
        Current Speed: Unknown
        Type: EDO DIMM
        Installed Size: 8192 MB (Single-bank Connection)

...while avoiding these "Not Installed" ones:

        Socket Designation: RAM socket #3
        Bank Connections: 3
        Current Speed: Unknown
        Type: DIMM
        Installed Size: Not Installed
        Enabled Size: Not Installed
        Error Status: OK

While I try to come up with a better regex that isn't so dang ugly, do you have any suggestions on improving it?

Update

Somewhat less ugly:

dmidecode | perl -le '$o = qr/[^\n]+\n[^\n]+/; $a = join "", <STDIN>; +$a =~ s/(Socket Designation: RAM($o){4}Installed Size: \d[^\n]+\n)/pr +int $1/smge'

Update #2

OK, this seems to be working on both VMware and physical... for future reference. Thanks goes out to everyone who pitched in. This is a big step forward.

dmidecode | perl -e 'undef $/; for ( split /(?<=\n)\n+/, <> ) { print +if /RAM socket|Memory Device/ && !/(Not|No Module) Installed/ }'
--
Tommy
$ perl -MMIME::Base64 -e 'print decode_base64 "YWNlQHRvbW15YnV0bGVyLm1lCg=="'

Replies are listed 'Best First'.
Re: grabbing dmidecode memory data - there's got to be a better way
by kennethk (Abbot) on Dec 28, 2012 at 19:19 UTC
    1. x is your friend. It will let you insert some white space to add legibility. Maybe not in the one-liner, but certainly during the regex development.
    2. m is your friend. You've got it enabled, but are not actually using it. It's ideal for specifying the end/start of lines that you are doing with $o
    3. s may not be your friend in this case. If you turn off s, then . actually corresponds to the character class [^\n].

    While this may not work for the full range of output in your particular case, maybe something like: dmidecode | perl -e 'undef $/;for (split /(?<=\n)\n+/, <STDIN>) {print if /RAM socket/ && !/Not Installed/}' would work. Keep it simple.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      Yes, that's cool! First slurp, then split on paragraph chunks, and finally simply match against keywords in the block. That's nice. Could you have not done that without the zero-width positive look-behind? Seems like that would be the best way, but I still wonder...

      --
      Tommy
      $ perl -MMIME::Base64 -e 'print decode_base64 "YWNlQHRvbW15YnV0bGVyLm1lCg=="'
        You could simplify the split to \n\n+ or something similar, but then you need to modify something else to keep the records newline separated. I'm willing to go to pretty extreme lengths to keep print if /RAM socket/ && !/Not Installed/ clean just because of personal taste. TIMTOWTDI.

        dmidecode | perl -e 'undef $/;/RAM socket/ && !/Not Installed/ && s/$/\n\n/ && print for split /\n\n+/, <>'


        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: grabbing dmidecode memory data - there's got to be a better way
by afoken (Chancellor) on Dec 28, 2012 at 19:10 UTC

    I prefer NOT to call external utilities writing "human readable" data. The output formats often change without announcement, they are not properly defined, and some stupid tools insist on doing their own pager or wrap lines. So, my first approach is to search CPAN for DMI (after all, dmidecode just reads some file(s) in /sys or /proc):

    The first one seems to read the DMI data directly (from /dev/mem, unfortunately, so it might need root privileges, whereas a tool reading from sysfs could live without root privileges), the other one attempts to parse dmidecode output.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      Well, in this particular environment I have root access, but can't install CPAN modules. They've got to be builtins, or none at all. I'm stuck scraping text for the time being, from a source format which WILL change without notice down the road, and already differs from one architecture to another.

      --
      Tommy
      $ perl -MMIME::Base64 -e 'print decode_base64 "YWNlQHRvbW15YnV0bGVyLm1lCg=="'
Re: grabbing dmidecode memory data - there's got to be a better way
by RichardK (Parson) on Dec 28, 2012 at 20:01 UTC

    Does using the quiet flag dmidecode -q make the job any easier?

    I'm certainly seeing less info to parse here :-)

      Yes, that does make for more concise output. After the regex that pulls the mem info into blocks, I'll have to do more work to pull out the useful bits for the higherups, namely socket, size, and locator. Less text will be easier (and faster) to process.

      Thanks.

      --
      Tommy
      $ perl -MMIME::Base64 -e 'print decode_base64 "YWNlQHRvbW15YnV0bGVyLm1lCg=="'

        dmidecode has even more useful switches:

        -s KEYWORD
        --string KEYWORD
        Only display the value of the DMI string identified by KEYWORD. [...]
        -t TYPE
        --type TYPE
        Only display the entries of type TYPE. TYPE can be either a DMI type number, or a comma-separated list of type numbers, or a keyword from the following list: bios, system, baseboard, chassis, processor, memory, cache, connector, slot. Refer to the DMI TYPES section below for details. [...]
        -u
        --dump
        Do not decode the entries, dump their contents as hexadecimal instead. [...]
        --dump-bin FILE
        Do not decode the entries, instead dump the DMI data to a file in binary form. [...]

        You could use -s and -t to filter inside dmidecode, so that you have less data to process.

        The -u switch generates a slightly more predictable format. You could decode the hexdumps inside perl, using knowledge from DMI::Decode (i.e. copy and port the C code from there to perl).

        The --dump-bin switch delivers the raw DMI data, which you could decode all by yourself, again by using knowledge from DMI::Decode.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)