2012-09-05 100 views
4

我有以下文本文件,我需要比較每行的值,即項目2-4與項目5-7中的值。我堅持使用bash/awk/sed。使用bash將一行中的字符串分配給變量

的樣本數據:

[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 

什麼是更有效的方法來實現這一目標?

+0

爲了完整起見,還要注意'set $ rec'會將第一個字段分配給'$ 1',第二個分配給'$ 2'等。 – tripleee

回答

6

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

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

完美。謝謝。 – user1117603

+3

或'$ 2 == $ 5 && $ 3 == $ 6 && $ 4 == $ 7 {print $ 1}'。 – Thor

+0

或者'$ 2 $ 3 $ 4 == $ 5 $ 6 $ 7 {print $ 1}'(稍微不夠強大,但是我相信可以滿足問題的限制。) –

5

您可以使用read將變量分配:

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

使用perl:

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

你確定嗎? 'perl -e'@ v =(0,1,2,1); print @v [0,1] eq @v [2,3]'' – choroba

+1

你不需要'split','-a' alread需要處理:'perl -lane'print $ F [0] if @F [1 ..3] ne @F [4..6]''。 – Thor

+1

有多種方法可以做到這一點(在Perl中)。 – 2012-09-05 12:24:32

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 
4

一些修正:

  1. 不要cat單個文件到管道;只是重定向循環的標準輸入。
  2. read可以將每一行分成合適的變量。
  3. 因爲您正在使用bash [[...]]構造,所以您不需要使用用單個字符前綴可能爲空的字符串的舊技巧。直接比較相應的值。

所以你的循環減少了

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}符號擴展到從索引xy元素。

相關問題