【问题标题】:need help on shell script for expected output需要有关 shell 脚本的帮助以获得预期的输出
【发布时间】:2019-01-31 09:40:13
【问题描述】:

我有一个名为 input.txt 的输入文件,如下所示:

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

我将文本提取到第一个字段中第一个大写字母之前的文本,并将这些 sn-ps 存储在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


【解决方案1】:

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

UPDATE 在 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

【讨论】:

  • 嗯,看来我的 bash 技能并没有我想象的那么生疏。添加了 Bash 解决方案...
  • @Mohan 我的解决方案没有创建output.txt,因为创建最终输出没有必要这样做。
  • 感谢您的脚本 Berker,这是保存输入/输出文件的正确方法。输入应该在 while 完成后,输出文件应该在 for 循环完成后声明 -A map -- > 这会做什么
  • @Mohan 您是说您需要带有键列表的中间 output.txt 吗?为什么?并不是说在提供的解决方案中很难将密钥列表转储到另一个文件中。请参阅bash 手册页中有关“关联数组”(也称为哈希、其他编程语言中的映射或目录)和define -A 中的Arrays 部分。
  • 我不想要键的输出(output.txt,),但我需要 output1.txt 文件的输出,因为我期望输出如下电源 power:powerOf|creating new file|failure, powerAp|powerof server|failureof file creat creat:creatEd|new file creation|failure 我还没有测试 bash 脚本,如果有任何错误,请回复你,谢谢你的帮助!!
【解决方案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 中),则附加上一个值和一个逗号,否则将数组值初始化为键本身和当前行之前的冒号。完成后,循环遍历累积的键并打印我们为每个键存储的值。

如果行很长,20,000 行可能一次无法放入内存,但如果您的示例具有代表性,即使在普通硬件上也应该是一项不起眼的任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2012-07-12
    • 2013-06-23
    • 2011-09-02
    • 1970-01-01
    相关资源
    最近更新 更多