2016-01-05 62 views
2

在我的文件中,每行包含由空格(前後有更多字段)分隔的五個數字字段。通過shell腳本,我需要能夠在這五個數字字段中正確選擇具有3,4和5個相同條目的行(即三個單獨的搜索,以便在這些字段中搜索具有3個匹配的行不會也返回行在這些領域有4或5場比賽)。選擇具有n個相同字段的行,在哨兵字符後

要查找相關字段,我的搜索必須找到第一個打開和關閉的圓括號對。括號結束後,緊跟在後面的五個字段是我感興趣的字段。一個潛在的複雜因素:有時一個或多個數字字段被單個短劃線/連字符替代,而不是數字。一種可能的簡化方法:五個字段將以(非嚴格)升序排列,並且任何連字符條目將始終位於其餘數字字段之前。

我將不勝感激這個一些sed/awk的建議。非常感謝!

[編輯]:我可以提取相關字段(詳見下面的評論),因此上面的透視段落是不必要的。下面是示例數據一旦相關字段提取:

109 110 111 111 112 
110 110 111 111 112 
99 99 99 112 112 
99 99 99 112 112 
100 101 101 112 112 
102 102 102 112 112 
102 102 103 112 112 
102 103 103 112 112 
102 104 104 112 112 
102 104 104 112 112 
103 104 104 112 112 
102 105 105 112 112 
102 105 105 112 112 
103 105 105 112 112 
102 106 106 112 112 
102 106 107 112 112 
103 106 107 112 112 
104 106 107 112 112 
102 107 107 112 112 
104 107 107 112 112 
104 107 107 112 112 
106 107 108 112 112 
107 107 108 112 112 
107 107 108 112 112 
102 109 109 112 112 
102 109 109 112 112 
104 109 109 112 112 
102 109 110 112 112 
103 109 110 112 112 
104 109 110 112 112 
102 110 110 112 112 
104 110 110 112 112 
104 110 110 112 112 
107 109 111 112 112 
107 109 111 112 112 
106 110 111 112 112 
107 110 111 112 112 
107 110 111 112 112 
109 110 112 112 112 
110 110 112 112 112 
107 112 112 112 112 
112 112 112 112 112 

這應該產生命中時在這些線路上n = 3時:

99 99 99 112 112 
99 99 99 112 112 
102 102 102 112 112 
109 110 112 112 112 
110 110 112 112 112 

命中在這條線,當n = 4:

107 112 112 112 112 

和一個在這條線,當n = 5命中:

112 112 112 112 112 
+2

歡迎來到StackOverflow!要[完成您的問題](http://stackoverflow.com/posts/34602978/edit),請包含可用的示例數據,您正在查找的輸出示例,您迄今爲止編寫的代碼以及輸出(或錯誤)代碼生成。我們只會樂意幫助你,但*你的代碼*是一個起點。 – ghoti

+0

@ghoti是否有UI方式來插入文本,或者你只是手動粘貼它? –

+0

我寫的代碼迄今爲止只隔離了五個字段: 'cat myfile | cut -d')'-f 2 | sed -e's/^ [\ t] * //'| tr -s''|切-d''-f1-5' 我真的不知道匹配部分從哪裏開始。但是我應該簡化這個問題,所以它只會詢問如何在5個字段中找到具有n個匹配字段的行,作爲我可以解決的「哨兵」問題。謝謝。 – user3575075

回答

2

這是一個使用awk的Bash腳本解決方案。它逐行讀取文件並使用AWK associative array來計算該行上出現的數字的次數。將filename.txt更改爲包含數字的文件。

n=3 
while read line 
do 
    echo "$line" | awk -v n="$n" ' 
     { 
      for(i=1; i <= NF; i++) { 
       a[$i]++ 
      } 
     } 
     { 
      for(o in a) { 
       if (a[o] == n) { 
        print 
       } 
      } 
     } 
     ' 
done < filename.txt 
+1

謝謝你,作品精美。我無法相信訪問關聯數組成員的語法有多簡單。 – user3575075

+0

我可以建議,不要使用'-v'選項將變量引用到awk中,而不是轉義引用'$ n'? 'awk -v n =「$ n」'this {that}''。另外,要小心使用'printf'。如果'$ line'(偶然不存在於awk腳本的範圍內)包含格式化字符,則會得到不可預知的結果,很可能是錯誤。 – ghoti

+0

@ghoti謝謝,我不知道那個Awk功能。我更新了我的答案,並將'printf'改爲'print'。 – badjr

2

您也可以使用sed來做到這一點。 您可以創建一個script

n=$(($1-1)) 
sed -n "/\([0-9]*\)\(\1\)\{$n\}/p" filename 

而像這樣運行它,只需提供n作爲腳本參數:

./script.sh 3 

輸出:

99 99 99 112 112 
99 99 99 112 112 
102 102 102 112 112 
109 110 112 112 112 
110 110 112 112 112 
+0

謝謝你,這些精簡的腳本正是那種讓我覺得我需要徹底學習sed並且同時讓我絕望達到那個點的東西,作爲一個愛好者,只需要按照每年一次的順序完成這些任務。 – user3575075

+0

歡迎您,您其實不需要學習sed,您需要了解正則表達式,它對於所有語言的工作方式都是相同的 – tinySandy

2

另一個SED例子,沒」不要我的工作去浪費;)

#!/bin/bash 
while (($1 > 0)) 
do 
    n="${n} \1" 
    set ${1}-1 
done 
sed -nr "\_\<([0-9]+)${n}\>_ p" 

編輯: 在BSD sed(OS X),你需要與迷人[[:<:]][[:>:]]分別替換\<\>

2

AWK-只是作爲一個班輪解決方案:

awk -v n=3 '{for(i=1;i<=NF;i++)a[$i]++;for(o in a)if(a[o]==n)p=1} p; {p=0;delete a}' inputfile 

拆分出來,方便閱讀,這種略帶類似於badjr的解決方案。 (我用他的變量爲方便比較。)

{ 
    for (i=1;i<=NF;i++)  # populate an array with counts of unique elements 
    a[$i]++ 
    for (o in a)   # check the array for a matching count & set flag 
    if (a[o]==n) 
     p=1 
} 

p;  # if we've set our flag, print the current line. 

{  # clear our workspace for the next line. 
    p=0 
    delete a 
} 

如果你有興趣在純bash的解決方案,以下實現相同的邏輯awk的,只是沒AWK:

#!/usr/bin/env bash 

n=5 

while read -a a; do 
    unset b 
    for i in "${!a[@]}"; do 
    ((b[${a[$i]}]++)) 
    done 
    for i in "${b[@]}"; do 
    [ "$i" -eq "$n" ] && echo "${a[@]}" 
    done 
done < inputfile 

請注意,因爲這裏的輸出是使用數組元素打印的,所以輸入文件中的空白不會被保留。

該解決方案由於使用陣列而僅限bash。

相關問題