使用bash将行中的字符串分配给变量

时间:2012-09-05 10:17:01

标签: bash sed awk

我有以下文本文件,我需要比较每行的值,即项目2-4与项目5-7。我坚持使用bash / awk / sed。

示例数据:

[hartford tmp]$ cat flist
a1 1 2 3 x y z
b1 3 2 1 z y x
c1 1 2 3 1 2 3
d1 4 5 6 6 5 4
e1 a b c a b c
f1 x y z x y z

它适用于以下脚本,但它的速度令人难以忍受,可能是因为所有echo s。

[hartford tmp]$ cat pdelta.sh
#!/bin/bash

cat flist |while read rec; do
    f1="$(echo $rec | awk '{ print $1 }')"
    f2="$(echo $rec | awk '{ print $2 }')"
    f3="$(echo $rec | awk '{ print $3 }')"
    f4="$(echo $rec | awk '{ print $4 }')"
    f5="$(echo $rec | awk '{ print $5 }')"
    f6="$(echo $rec | awk '{ print $6 }')"
    f7="$(echo $rec | awk '{ print $7 }')"

    if [[ "x${f2} x${f3} x${f4}" != "x${f5} x${f6} x${f7}" ]]; then
            echo "$f1 DOES NOT MATCH"
    fi
done

运行时,输出正是我正在寻找的,但在处理50k +行长的文件时输出太慢。

[hartford]$ ./pdelta.sh
a1 DOES NOT MATCH
b1 DOES NOT MATCH
d1 DOES NOT MATCH

有什么更有效的方法来实现这一目标?

5 个答案:

答案 0 :(得分:6)

您可以使用awk输出所有匹配的ID:

awk '{ if ($2 == $5 && $3 == $6 && $4 == $7) { print $1 } }' < flist

答案 1 :(得分:5)

您可以使用read分配变量:

$ while read f1 f2 f3 f4 f5 f6 f7; do stuff; done <flist

答案 2 :(得分:4)

一些修正:

  1. 不要将cat个文件放入管道;只需重定向循环的标准输入。
  2. read可以将每一行拆分为适当的变量。
  3. 由于您使用的是bash [[...]]构造,因此您不需要使用带有单个字符的可能为空的字符串前缀的旧技巧。只需直接比较相应的值即可。
  4. 所以你的循环减少到

    while read f1 f2 f3 f4 f5 f6 f7; do
        if [[ $f2 != $f5 || $f3 != $f6 || $f4 != $f7 ]]; then
            echo "$f1 DOES NOT MATCH"
        fi
    done < flist
    

    您还可以使用数组进一步减少

    while read -a f; do
        if [[ ${f[@]:1:3} != ${f[@]:4:3} ]]; then
            echo "${f[0]} DOES NOT MATCH"
        fi
    done < flist
    

    ${f[@]:x:y}符号从索引y开始扩展为x个元素。

答案 3 :(得分:2)

使用perl:

perl -lane 'print $F[0] if @F[1..3] ne @F[4..6]' input_file

答案 4 :(得分:0)

Python解决方案:

import sys

for line in sys.stdin:
    f1, f2, f3, f4, f5, f6, f7 = line.split()
    if not (f2, f3, f4) == (f5, f6, f7):
        print f1, "does not match"

用法:

$ python f.py < flist
a1 does not match
b1 does not match
d1 does not match