0
4

5 回答 5

4

While I personally go for awk as a first recourse for this sort of thing, the code you use there is perhaps not as general as you'd like. In particular, by setting the field separator as you've done, you run the risk of it getting recognized on the right-hand side of your property lines, making $2 not actually be the full property value. I think you'd probably be better off avoiding using FS at all and doing something like the following, which operates on the full original line(s):

awk '{ sub(/^[^:]*:[:blank:]*/, ""); print }'

which is the slightly abbreviated version of:

awk '{ sub(/^[^:]*:[:blank:]*/, "", $0); print $0; }'

That is, remove (replace with the empty string) from the line ($0) everything up to the first colon followed by zero or more blanks. Print the result.

For a bash version, I'd use the match operator available in [[ expressions. The variable name you have to use for extracted sub-expressions is a bit verbose, but I like that I can use less quirky (or at least the usual expected quirks of) regular expression syntax:

[[ $v =~ ^[^:]*:[:blank:]*(.*) ]] && echo "${BASH_REMATCH[1]}"

The regex here is mostly the same as the one used in the awk version above.

于 2013-04-03T05:10:30.183 回答
3

Another Perl version:

lsb_release -d | perl -pe 's/^[^:]*:\s*//;s/\s*$//;'
于 2013-04-02T23:49:18.950 回答
1

Perl has a module available to parse Commons Configuration files. As an (overengineered) one-liner:

lsb_release -d | perl -MConfig::Properties::Commons -E'say Config::Properties::Commons->new(load_file=>\*STDIN)->get_property("Description")'

As a normal script:

#!perl
use strict; use warnings; use 5.010;

use Config::Properties::Commons;

my $cpc = Config::Properties::Commons->new;
$cpc->load($ARGV[0] // \*STDIN);

say $cpc->get_property("Description");

Without that module, I would use split:

split /:\s*/, $_ would split on any colon and remove all following whitespace,
split /:\s*/, $_, 2 will split the string into two pieces max (so the value can include colons),
and (split /:\s*/, $_, 2)[1] will return the second fragment. Therefore

lsb_release -d | perl -lne's/\s*$//, print for (split /:\s*/, $_, 2)[1]'

would work as well.

于 2013-04-03T01:04:46.717 回答
1

I guess this could still be considered a one-liner:

lsb_release -d|php -r "echo trim(end(explode(':', file_get_contents('php://stdin'), 2)));"

Sadly PHP doesn't have a shorthand to handle fetching from stdin ;-)

于 2013-04-03T05:14:23.613 回答
1

If you truly want to actually parse text like you described, you could use YAML::XS.

$ lsb_release -d | perl -MYAML::XS -E'local $/;say Load(<>)->{Description}'
Ubuntu 12.04.2 LTS
$ perl -MYAML::XS -MData::Printer -E'p Load(do{local $/;<>})'
key1: value1
key2: value2
^d
\ {
    key1   "value1",
    key2   "value2"
}

(^d represents pressing Ctrl + d)

The output of Data::Printer is actually more colorful than can be reproduced here.

于 2013-04-03T15:04:21.267 回答