需要在shell脚本帮助预期的输出

问题描述 投票:1回答:2

我有一个名为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行。我不知道为什么我收到重复的输出。我究竟做错了什么?

linux shell grep
2个回答
2
投票

击的解决方案:

#!/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后更新已重述原来的问题。解第一环路仅包括输入,而不是整个行的第二列中:

    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

2
投票

分解出useless uses of 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的话)的关键,追加前值和一个逗号,否则初始化数组值的密钥本身,以及电流线前一个冒号。当我们完成后,通过循环累计键和打印的价值,我们存储每个。

若线长,2万行可能不适合到内存中一次,但如果你的榜样代表,应该是最温和的硬件一个不起眼的任务。

© www.soinside.com 2019 - 2024. All rights reserved.