нужна помощь по сценарию оболочки для ожидаемого вывода - PullRequest
0 голосов
/ 31 января 2019

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

powerOf|creating new file|failure
creatEd|new file creating|failure
powerAp|powerof server|failureof file

Я извлекаю текст до первой буквы в первом поле и сохраняю эти фрагменты в output.txt:

power
creat

Я использовал команду sed для разделения значений, и она работает нормально.

Из выходного файла (output.txt) мне нужно grep от первогополе и выходные данные должны быть такими, как показано ниже:

Power
power:powerOf|creating new file|failure,powerAp|powerof server|failureof file
creat
creat:creatEd|new file creating|failure

Я пробовал несколько способов, но я не получаю ожидаемый результат.

Я пробовал следующее, но я получаю дубликатзаписи:

cat input.txt | cut -d '|' f1 >> input1.txt
cat input1.txt | s/\([a-z]\)\([A-Z]\)/\1 \2/g >> output.txt
while read -r line;do
  echo $ line
  cat input.txt |cut -d ‘|’ f1|grep $line >> output1. txt
done< "output.txt"

У меня есть 20000 строк во входном файле.Я не знаю, почему я получаю дубликаты на выходе.Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 31 января 2019

С учетом бесполезного использования cat и других антипаттернов, вы в основном делаете

# XXX not a solution, just a refactoring of your code
sed 's/\([a-z]\)\([A-Z]\).*/\1/' input.txt | grep -f - input.txt

, который просто извлекает строки, но ничего не делает, чтобы присоединиться к ним.Если вы хотите объединить строки с одинаковыми значениями префикса, простой скрипт Awk, вероятно, сделает то, что вам нужно.

awk '{ key=$1; sub(/[A-Z].*/, "", key)
      b[key] = (key in b ? b[key] "," : key ":" ) $0 }
    END { for(k in b) print b[k] }' input.txt

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

Если строки длинные, 20000 строк могут не поместиться в память сразу, но если ваш пример является представительным, следуетбыть ничем не примечательной задачей даже на скромном оборудовании.

0 голосов
/ 31 января 2019

Решение Bash:

#!/bin/bash
keys=()
declare -A map
while read line; do
    key=$(echo ${line} | cut -d \| -f1 | sed -e 's/[[:upper:]].*$//')
    if [[ -z "${map[$key]}" ]]; then
        keys+=(${key})
        map[$key]="${line}"
    else
        map[$key]+=",${line}"
    fi
done

for key in ${keys[*]}; do
    echo "${key}"
    echo "${key}:${map[$key]}"
done

exit 0

Возможно, решение Perl приемлемо и для OP:

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

my @keys;
my %map;
while (<>) {
    chomp;
    my($key) = /^([[:lower:]]+)/;
    if (not exists $map{$key}) {
        push(@keys, $key);
        $map{$key} = [];
    }
    push(@{ $map{$key} }, $_);
}

foreach my $key (@keys) {
    print "$key\n";
    print "$key:", join(",", @{ $map{$key} }), "\n";
}


exit 0;

Тестирование с заданным вами значением:

$ perl dummy.pl <dummy.txt
power
power:powerOf|creating new file|failure,powerAp|powerof server|failureof file
creat
creat:creatEd|new file creating|failure

ОБНОВЛЕНИЕ после того, как OP повторно изложил исходную проблему.Решение для первого цикла, который включает в себя только 2-й столбец ввода вместо всей строки:

    message=$(echo ${line} | cut -d \| -f2)
    if [[ -z "${map[$key]}" ]]; then
        keys+=(${key})
        map[$key]="${message}"
    else
        map[$key]+=",${message}"
    fi

Проверка с заданным входом:

$ perl dummy.pl <dummy.txt
power
power:creating new file,powerof server
creat
creat:new file creating
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...