[英]awk: using column variable as a pattern
我有一個類似值的表格,不幸的是格式不同(我的控制之外),我想只想要那些$ 1和$ 2完全不同的行。 我關注的兩個主要問題是:
1)我沒有運氣
awk '$1 !~ /$2/' filename
甚至部分完成這項任務; 它產生一個空集。 我感覺這是我寫/ $ 2 /部分的方式,但是找不到不產生空集或錯誤的格式。
2)整個電路板的格式差異並不相同。 以下是輸入示例:
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
我只想返回具有明顯不同值的行,如下所示:
Q012345 D666666
q12345 23588
一縷希望似乎是每對列都有相同的數字序列,如果字母有時會忽略前面的0。 任何幫助,將不勝感激。 如果它有幫助,那就是korn shell。
更新:我看到我犯了一個常見的錯誤,就是假設每個人都知道我在說什么是沒有充分理由的。 通過“明顯不同”,我的意思是前面0的值中的數字是不同的。 輸入后,我意識到這些字母對於我對此數據執行的特定任務實際上毫無意義。 因此q12345和12345對於我的目的是相同的,並且012345和12345是相同的,但12345和78945不是,也不是12345和12346。
現在我輸入了這個,是否只有一種簡單的方法可以只返回每列中的數字,以便只比較數字? 這樣,前面的零將毫無意義(012345 = 12345),我會得到我想要的東西。 對不起任何困惑。
如果模式包含在變量中,請不要使用斜杠 - 使用斜杠來包含靜態正則表達式。 你要
awk 'tolower($1) !~ tolower($2)' filename
使用tolower
啟用不區分大小寫的匹配。 或者如果您使用的是GNU awk:
gawk -v IGNORECASE=1 '$1 !~ $2' filename
嗯,它確實取決於你所說的“完全不同”的含義。 我的意思是,你可以通過以下方式前進和后退子串匹配:
#!/usr/bin/env perl
use strict;
use warnings;
while ( <DATA> ) {
my ( $first, $second ) = split;
print unless ($first =~ /$second/i or $second =~ /$first/i);
}
__DATA__
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
哪個會給你:
Q012345 D66666
q12345 23588
這個單線程如下:
perl -lane 'print unless ( $F[0] =~ /$F[1]/ or $F[1] =~ /$F[0]/ )'
或者你可以根據'Levenshtein距離'來做到這一點:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::Levenshtein qw(distance);;
while ( <DATA> ) {
my ( $first, $second ) = split;
print unless distance ( $first, $second ) < 3;
}
__DATA__
q12345 12345
Q012345 D66666
q12345 Q12345
Q012345 12345
q12345 23588
注意 - Q012345 - > 12345是Levenshtein距離2,因此您可以調整相似度。
注意 - 我知道你已經標記了awk
並詢問了korn
shell。 我給了perl
,因為它通常在“korn”或“awk”時可用。
您可以替換上面的__DATA__
,這對於創建一個自包含的示例非常有用:
while ( <> ) {
my ( $first, $second ) = split;
#etc .
}
<>
是神奇的文件句柄,就像你期望的那樣工作grep,sed或awk - 讀取stdin或命令行中指定的文件,這樣你就可以:
cat somefile | script.pl
要么
script.pl somefile
在任何一種情況下它都會做正確的事情。
鑒於修改后的描述,這似乎完成了工作(示例數據位於我的機器上稱為data
的文件中),但我承認可能有更緊湊的方法來實現相同的結果:
$ awk 'substr($1, match($1, /[0-9]+/)) +0 != substr($2, match($2, /[0-9]+/)) + 0 { print }' data
Q012345 D66666
q12345 23588
$
match
和substr
函數是為POSIX awk
定義的。 match
函數返回第一個參數中正則表達式開頭的偏移量,因此它返回$1
或$2
第一個數字的索引。 substr
返回從該位置開始的字符串。 + 0
確保以數字方式處理這些值(因此忽略前導零) - 沒有這一點,也報告了Q012345 12345
線。
在Mac上測試(macOS Sierra 10.12.13,帶有本機(BSD) awk
和GNU awk
)。
我想我遇到了類似的情況,下面的另一張海報的答案我可能有一些奇怪/舊的Awk實現。 代碼一直返回非法語句錯誤。 這個版本的Awk沒有
match
......
這只適用於sub
,它將一個正則表達式應用於一個變量,並替換匹配的內容,在本例中為空字符串,從而刪除字段開頭的非數字(或者,如果有數字,則開始,但非數字之后,它會刪除那些;天堂幫助你,如果你有一個字段1234-5678-99
因為你最終將12345678與其他字段進行比較)。 還有gsub
可以反復應用搜索和替換。
$ awk '{ v1 = $1; sub(/^[^0-9]*/, "", v1); v2 = $2; sub(/^[^0-9]*/, "", v2); if (v1 + 0 != v2 + 0) print }' data
Q012345 D66666
q12345 23588
$
如果您還沒有sub
或gsub
,那么(a)請確定平台 - o / s和版本 - 以及Awk的版本,以及(b)請獲取並安裝GNU Awk,這樣您就不必為了像這樣。 如果這是一個問題,請提供您所擁有的Awk版本的在線文檔的鏈接,並且很可能是另一種解決方案。
如果您在Solaris上,請嘗試使用nawk
(新的Awk)而不是oawk
(舊的Awk) - 其中awk
可能是oawk
或nawk
的鏈接。 如果這是問題,請重新調整系統以使nawk
成為默認值。
也許我誤解了這個問題,但似乎你只需要:
$ awk '{x=$0; gsub(/[^0-9 \t]/,"")} $1!=$2{print x}' file
Q012345 D66666
q12345 23588
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.