如何组合文件并搜索结果?

时间:2015-09-04 17:15:35

标签: linux bash shell sed

我有两个示例文件,如下所示:

File1中

item name="NY" block="A" idnum="12345"
item name="NJ" block="B" idnum="123456"
item name="CT" block="C" idnum="1234567"

文件2

ID_B|ID_C|NY|4|8198|10|2374|127
ID_C|ID_D|NJ|4|8198|10|2374|127
ID_D|ID_E|CT|4|8198|10|2374|127

我希望能够生成一个文件作为参数传递ID,输出应该如下所示

如果我正在寻找ID_B的信息,那么输出应为

ID_B|ID_C|NY|4|8198|10|2374|127 => "NY" block="A" idnum="12345"

如果我一起寻找两个ID_CID_D,那么它应该是

ID_C|ID_D|NJ|4|8198|10|2374|127 => "NJ" block="B" idnum="123456"
ID_D|ID_E|CT|4|8198|10|2374|127 => "CT" block="C" idnum="1234567"

5 个答案:

答案 0 :(得分:2)

这样的东西
echo "Please enter the key"
read key
grep "item name=\"$(grep "^${key}|" file2 | cut -d"|" -f3)\"" file1

编辑: 我没有做文字输出,只是想表明你可以grep字段。完整的解决方案应如下所示:

#!/bin/bash
if [ $# -eq 0 ]; then
   echo "Usage $0 id [id2 ..]"
   exit 1
fi

for key in $*; do
   f2=$(grep "^${key}|" file2 )
   f1=$(grep "item name=\"$(echo "^${f2}" | cut -d"|" -f3)\"" file1 )
   echo "${f2} => ${f1#item name=}"
done

答案 1 :(得分:2)

使用bash,join,sort和awk。

script.sh:

#!/bin/bash

file1="File1"
file2="File2"

grep -f <(printf "^%s|\n" "$@") <(join -t '|' -1 1 -2 3 <(awk -F'"' '{OFS="|"; print $2,$4,$6}' "$file1" | sort -t '|' -k 1,1) <(sort -t '|' -k 3,3 "$file2") -o 2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.3,1.2,1.3 | awk -F'|' '{ printf "%s|%s|%s|%s|%s|%s|%s|%s => \"%s\" block=\"%s\" idnum=\"%s\"\n",$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11 }')

示例:script.sh ID_C ID_D

输出:

ID_D|ID_E|CT|4|8198|10|2374|127 => "CT" block="C" idnum="1234567"
ID_C|ID_D|NJ|4|8198|10|2374|127 => "NJ" block="B" idnum="123456"

答案 2 :(得分:1)

awk,包裹在一个瘦的shell脚本中

#!/bin/sh
awk -F '[|"]' -v OFS='"' -v keys="$*" '
    BEGIN { 
        n = split(keys, a, " ") 
        for (i=1; i <= n; i++) key[a[i]] = 1
    }
    NR == FNR {
        if ($1 in key) line[$3] = $0
        next
    }
    $2 in line {
        $1 = line[$2] " => "
        print
    }
' file2 file1

然后

$ sh script.sh ID_B ID_D
ID_B|ID_C|NY|4|8198|10|2374|127 => "NY" block="A" idnum="12345"
ID_D|ID_E|CT|4|8198|10|2374|127 => "CT" block="C" idnum="1234567"

答案 3 :(得分:0)

你想要什么,与SQL中的JOIN非常相似。

不幸的是,在bash,awk或sed等过程语言中实现它需要字典或字符串索引字符串数组。 (即使使用它们,它也会像单行sql查询一样复杂得多。)它们都不支持它,尽管有很多可能模仿它。

在你的位置我会使用perl或python来解决这个问题 - 在这些语言上你的目标就是如此简单,即使有额外的学习努力,它也会像bash一样有效。

但是你想要一个bash-awk-sed解决方案,所以这就是我现在给你的。

不要单独使用这些语言,请将它们集成使用。在bash中你可以做的最简单的事情是使用外部命令grep

例如,一个集成的awk / bash核心部分完成了你的任务(我没有对它进行过测试):

awk 'BEGIN {FS="[_|]"} { print $2 " " $0}' file1|while read l
do
  set $l
  echo $2 $(grep 'block="'$1'"' file2)
done

但是要理解这段代码,调试它并扩展它,你需要有一个regexp的经验,转义的确切细节,以及如何将它们集成到这两种语言上是最快的。在我看来,如果你正在学习编程,那么在你开始学习perl / python之前它是必须的,但在日常工作中,更高级别的解决方案更好。

答案 4 :(得分:0)

您还可以编写一个简短的bash脚本,以蛮力的方式检索信息:

#!/bin/bash

[ -z "$1" -o -z "$2" -o -z "$3" ] && {
    printf "error: insufficient input. Usage: %s file1 file2 query\n" ${0##*/}
    exit 1
}

file1="$1"
file2="$2"
query="$3"

## line from file1
f1=$(grep "$query" "$file1")
[ -z "$f1" ] && {
    printf "error: '%s' not found in '%s'\n." "$query" "$file1"
    exit 1
}

## line from file2
f2=$(grep $(awk -F '|' '{ print $3 }' <<<$f1) "$file2")
[ -z "$f1" ] && {
    printf "error: no related row found in '%s'\n." "$file2"
    exit 1
}

printf "%s => %s\n" "$f1" "$f2"

<强>实施例

$ bash joinfiles.sh join1.txt join2.txt ID_B
ID_B|ID_C|NY|4|8198|10|2374|127 => item name="NY" block="A" idnum="12345"

$ bash joinfiles.sh join1.txt join2.txt ID_E
ID_D|ID_E|CT|4|8198|10|2374|127 => item name="CT" block="C" idnum="1234567"

$ bash joinfiles.sh join1.txt join2.txt ID_F
error: 'ID_F' not found in 'join1.txt'

处理多个输入标记

通过小幅调整,您可以轻松处理任意数量的标签。下面,代码将匹配作为参数3及更高版本提供的所有标记。如果您希望一次提供多个半打瞌睡的标签,那么您应该调整脚本以从stdin读取标签,而不是将它们作为参数。另请注意,代码与第一个文件的第一个字段中的标记匹配。如果要匹配文件一中所有字段中的标记,则f1将成为一个数组,代码的其余部分将对f1中的每个元素进行操作。让我知道你在想什么。以下是多个输入标记作为参数的示例:

#!/bin/bash

[ -z "$1" -o -z "$2" -o -z "$3" ] && {
    printf "error: insufficient input. Usage: %s file1 file2 query\n" ${0##*/}
    exit 1
}

[ -f "$1" -a -f "$2" ] || {
    printf "error: file not found.  '%s' or '%s'\n" "$1" "$2"
    exit 1
}

file1="$1"
file2="$2"

for i in "${@:3}"; do

    query="$i"

    ## line from file1
    f1=$(grep "^$query" "$file1")
    [ -z "$f1" ] && {
        printf "error: '%s' not found in '%s'\n." "$query" "$file1"
        exit 1
    }

    ## line from file2
    f2=$(grep $(awk -F '|' '{ print $3 }' <<<$f1) "$file2")
    [ -z "$f1" ] && {
        printf "error: no related row found in '%s'\n." "$file2"
        exit 1
    }

    printf "%s => %s\n" "$f1" "$f2"

done

使用/输出

$ bash joinfiles2.sh join1.txt join2.txt ID_B ID_D ID_F
ID_B|ID_C|NY|4|8198|10|2374|127 => item name="NY" block="A" idnum="12345"
ID_D|ID_E|CT|4|8198|10|2374|127 => item name="CT" block="C" idnum="1234567"
error: 'ID_F' not found in 'join1.txt'