Извлечение определенных значений имени столбца с помощью sed / awk / perl - PullRequest
1 голос
/ 27 октября 2009

У меня есть входной файл, например:

a=1 b=2 c=3 d=4
a=2 b=3
a=0 c=7
a=3 b=9 c=0 d=5
a=4 d=1
c=9

Предположим, что порядок имен столбцов (a, b, c и d) остается неизменным. Как мне написать скрипт / команду, которая поможет мне извлечь значения, специфичные для столбцов b и d? Таким образом, мой вывод должен быть:

b=2 d=4
b=3

b=9 d=5
d=1

Я мог бы написать "не очень хорошую" команду awk с использованием нескольких разделителей, чтобы отфильтровать их, используя каналы для использования опции -F, но я уверен, что есть и более элегантный способ сделать это.

Пожалуйста, помогите.

Ответы [ 8 ]

5 голосов
/ 27 октября 2009
sed 's/[^bd]=[0-9]* *//g'
3 голосов
/ 27 октября 2009
# awk '{ for(i=1;i<=NF;i++){if($i~/(b|d)=/){printf $i" "} }print ""}' file
b=2 d=4
b=3

b=9 d=5
d=1
3 голосов
/ 27 октября 2009
perl -pe 's/[^bd]=\d+ *//g' data_file
2 голосов
/ 27 октября 2009

Вот однострочная версия:

$ perl -lpe '@x=/([bd]=[0-9])/g; $_="@x"' test.txt

m//g в контексте списка возвращает все совпадения в виде списка.

#!/usr/bin/perl
use strict; use warnings;

while ( <DATA> ) {
    if( my @cols = /([bd]=[0-9])/g ) {
        print "@cols";
    }
    print "\n";
}

__DATA__
a=1 b=2 c=3 d=4
a=2 b=3
a=0 c=7
a=3 b=9 c=0 d=5
a=4 d=1
c=9

Выход:

C:\Temp> t.pl
b=2 d=4
b=3

b=9 d=5
d=1
1 голос
/ 27 октября 2009

Предполагая, что вы захотите что-то сделать со значениями в будущем, кроме простой фильтрации, вы можете использовать это как основу.

#! /usr/bin/env perl
use warnings;
use strict;

my @lines;

while(<>){
  my %kv = /([a-z])=([0-9])/ig;
  push @lines, \%kv;
}

for my $kv (@lines){
  # $kv->{a} ||= 1;
  # next unless $kv->{c};

  print "b=$kv->{b} " if defined $kv->{b};
  print "b=$kv->{d} " if defined $kv->{d};
  print "\n";
}
1 голос
/ 27 октября 2009

в рубине:

#!/usr/bin/env ruby
filename = ARGV[0]
fields = ARGV[1..ARGV.length]

File.open(filename) do |file|
  file.each_line do |line|
    pairs = line.split(' ').map { |expression| expression.split('=') }
    value_hash = Hash[pairs]

    requested_fields = []

    fields.each do |field|
      requested_fields << "#{field}=#{value_hash[field]}" unless value_hash[field].nil?
    end

    puts requested_fields.join(' ')
  end
end

Звоните, используя ruby ruby_script_name.rb input_file.txt field1 field2.

Мне нравится, насколько коротким является решение sed / perl, но насколько легко его можно изменить, чтобы оно занимало более длинные имена полей? Похоже, регулярное выражение быстро станет грязным ... В любом случае, эта стратегия будет применима и здесь, если вы захотите ее использовать.

1 голос
/ 27 октября 2009

Сед сделает это очень хорошо:

sed -e 's/[^bd]=[^ ]*//g' -e 's/^ *//' -e 's/ *$//' &lt filename

Первое регулярное выражение очищает ненужные поля (все, кроме b и d), так что вот где его можно изменить, если вы передумаете. Два других удаляют начальные и конечные пробелы.

0 голосов
/ 29 октября 2009

Очевидно, PostScript - это путь ... XD

(%stdin) (r) file
{
    dup 100 string readline not {exit} if
    {
        dup () eq {pop exit} if
        token pop 3 string cvs
        dup 0 get << 98 / 100 / >> exch known
        {print ( ) print} {pop} ifelse
    } loop
    / =
} loop

Использование: gs -q -dNOPROMPT -dNODISPLAY -dBATCH thisfile.ps < input

Примечания: замените << 98 / 100 / >> соответствующими значениями ASCII (98 = b, 100 = d), за которыми следует косая черта, разделенная пробелами (хотя вам не нужно использовать косую черту; это просто фиктивный объект ). Например, чтобы выбрать «c», «e» и «f», используйте << 99 / 101 / 102 / >>

Каждая строка может содержать не более 100 символов; если ваши строки длиннее, замените 100 string на большее число. Аналогично замените 3 string, если ваши записи x=# длиннее трех символов. Это не работает, если x больше, чем один символ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...