Извлечение фиксированной ширины записывает без разделителя от одной строки

Это выполнит то, что Вы спрашиваете:

awk -F';' '{print $1 ";" $2 ";" $3;}' <input >output

awk утилита хорошо разработана для этой задачи. Это может легко сократить отдельные строки в поля, затем управлять ими на основе этого. -F';' аргумент говорит awk использовать ; как разделитель полей. Кавычки необходимы, потому что оболочка интерпретировала бы ; как разделитель команды без них.

Команда, данная awk для выполнения для каждой строки ( '{print $1 ";" $2 ";" $3;}' бит), так же заключается в кавычки для хранения всех забавных символов ({, }, $, " и ; в этом случае) от того, чтобы быть рассматриваемым особенно оболочкой и удостоверяются, что все это передается awk как одна единица.

И, конечно, <input и >output директивы перенаправления, даваемые оболочке для перенаправления ввода и вывода команды от и до файла.

8
27.12.2013, 22:41
3 ответа

Как насчет

grep -oE 'A1.{10}|B1.{4}|C1.{7}' input.txt

Это печатает каждую запись каждого типа записи на отдельной строке. Перенаправить grep вывод в 3 файла называют A1, B1, C1 соответственно,

grep -oE 'A1.{10}|B1.{4}|C1.{7}' input.txt| 
awk -v OFS= -v FS= '{f=$1$2; $1=$2=""; print>f}'
5
27.01.2020, 20:10
  • 1
    за это. Вы возражаете объяснять эти различные компоненты сценария и переключатели, используемые так, чтобы я мог протестировать и расшириться. Также, как я добавляю шаблон 9 с перед ним (который в действительности будет алфавитно-цифровыми символами 7 символов в длину).Большое спасибо. –  jags 14.12.2013, 11:14
  • 2
    Говорил слишком скоро... Я должен был также добавить 1 важную информацию, которая была, что pattern.recordmarker мог бы появиться в остальной части записи, таким образом, его советовал, чтобы мы разделили запись за один раз на файл и повторно опросили файл, который, вероятно, означает, что я не могу использовать grep. –  jags 14.12.2013, 11:51
  • 3
    Кроме того, у меня есть 2 возможных решения. - пересекают через файл, маркировка с неясным символом для обозначения запускаются допустимой записи. Переместите X символов в зависимости от типа записи и используйте тот же неясный символ для обозначения следующей записи. Однако опасаясь любых буферных проблем. Поэтому ожидая, что новый вывод опросит сходство с этим"? \\9999999A1XXXXXXXXXX? \\9999999B1XXXX? \\9999999A1XXXXXXXXXX? \\9999999C1XXXXXXX" - используют текущую соль, но затем ищут в каждом выходном файле, если другие шаблоны появляются кроме, вначале –  jags 14.12.2013, 17:35
  • 4
    @jags, можно хотеть обновить исходный вопрос с данными действительно репрезентативной пробы, это все становится немного сбивающим с толку –  iruvar 14.12.2013, 20:00
  • 5
    1_CR, я повторно отправил вопрос. Спасибо всем за Вашу справку. Большинство ценившее. –  jags 14.12.2013, 23:34

Вот возможное решение с помощью FPAT простофили

BEGIN { 
    FPAT="A1.{10}|B1.{4}|C1.{7}" #define field contents
} 
{
    for(i=1;i<=NF;i++) 
        print $i >> substr($i,0,2) #print the field to file A1,B1,etc
}

Как острота:

gawk 'BEGIN{FPAT="A1.{10}|B1.{4}|C1.{7}"} {for(i=1;i<=NF;i++)print $i >> substr($i,0,2)}' < datafile
4
27.01.2020, 20:10

В Perl:

#!/usr/bin/env perl

use strict;
use warnings;
use re qw(eval);

my %field_widths = (
    A1 => 10,
    B1 =>  4,
    C1 =>  7,
    #...(fill this up with the widths of your 38 record types)
);

# Make a regex of record types; sort with longest first as appropriate for
# ... regex alternation:
my $record_type_regex = join '|', sort { length($b) <=> length($a) } keys %field_widths; 

my %records;
my $marker_length=7; #Assuming the marker is 7 characters long
while(<>){
    chomp;
    while( # Parse each line of input
      m!
        (.{$marker_length})          # Match the record marker (save in $1)
        ($record_type_regex)         # Match any record type (save in $2)
        (
         (??{'.'x$field_widths{$2})} # Match a field of correct width
        )                            # Save in $3
       !xg){
        $records{$2}.="$1$2$3\n";
      }
}
for my $file (sort keys %records){
    open my $OUT,'>',$file or die "Failed to open $file for writing: $!\n";
    print $OUT $records{$file};
    close $OUT
}

Вызовите его как:

[user@host]$ ./myscript.pl file_of_data

Код протестирован и работы с Вашим данным входом.

Обновление

В Ваших комментариях Вы запросили "Unix, эквивалентный" вышеупомянутого. Я высоко сомневаюсь, там существует такая вещь, так как выражение Perl, используемое для парсинга строки, является очень неправильным выражением, и я сомневаюсь, что ванильные регулярные выражения могут проанализировать формат определенных данных: это слишком подобно известному типу выражения, которое regex не может проанализировать (соответствуйте любому количеству aсопровождаемый тем же количеством b).

В любом случае самый близкий подход "Unix", который я могу найти, является обобщением 1_CR's ответ. Необходимо отметить, что этот подход характерен для реализации GNU grep и поэтому не будет работать над большинством Нельдов. Подход Perl, наоборот, должен работать то же над любой платформой, что Perl продолжает работать. Вот мой предложенный GNU grep подход:

cat <<EOF \
| while read -r record width;do
    grep -oE ".{7}$record.{$width}" input_file\ #replace 7 with marker length
     >> "$record"
done
A1 10
B1 4
# enter your 38 record types
EOF

Обновление

На основе запросов OP в комментариях, вместо того, чтобы передать имя файла как параметр командной строки, это может быть открыто в рамках сценария как так:

open my $IN,'<',$input_file_name or die "Failed to open $input_file: $!\n";
while(<$IN>){ #instead of while(<>)
...

Это предполагает объявление переменной $input_file_name содержать, ну, в общем, входное имя файла.

Что касается добавления метки времени к имени выходного файла, можно использовать qx{} синтаксис: между фигурными скобками можно поместить любую команду Unix, которую Вы хотите, и она будет выполнена и ее чтение стандартного вывода назад вместо qx{} оператор:

open my $OUT,'>',"$file_".qx{date +%Y-%m-%d--%I:%M:%S%P}

qx оператор не ограничивается фигурными скобками, используйте свой любимый символ в качестве разделителя, просто удостоверьтесь, что это не находится в команде, которую необходимо выполнить:

qx<...>
qx(...)    
qx!...!    
qx@...@

и так далее...

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

Между прочим, это даст немного отличающуюся метку времени каждому файлу (если различием их времен создания, окажется, будет конечное число секунд). Если Вы не хотите это, можно сделать это на двух шагах:

my $tstamp = qx{...};
open my $OUT,'>',"$file_$tstamp" or die...;
4
27.01.2020, 20:10
  • 1
    Привет снова.... начиная действительно любить жемчуг. Просто имейте несколько niggly битов. 1. Как читать в файле в противоположность передаче в параметре командной строки. Попытка, но отказ использовать Eclipse выполненная конфигурация. 2. Как добавить некоторый текст к выходному $file имени файла. Большинство ценившее. –  jags 24.12.2013, 12:01
  • 2
    @jags в клуб :). Ответ обновляется. Посмотрите, помогает ли это. –  Joseph R. 24.12.2013, 12:24
  • 3
    Спасибо Joseph. Однако для последнего запроса я означал на самом деле добавлять, например, встречаться/добавлять метку времени к выходному имени файла. Текущие выходные файлы A1, B1 и C1 кода. Большое спасибо снова. –  jags 24.12.2013, 18:37
  • 4
    @jags я вижу. Посмотрите, помогает ли обновление. –  Joseph R. 25.12.2013, 13:36
  • 5
    Спасибо как всегда Joseph. Однако я имел в виду, добавляют к имени файла эффективной выходной мощности, которое в этом случае в настоящее время является A1, B1, C1, т.е. Я хочу добавить дату/метку времени, A1 _ <todays_date>, B1 _ <todays_date>, C1 _ <todays_date>.Большое спасибо. –  jags 27.12.2013, 19:24

Теги

Похожие вопросы