簡體   English   中英

從shell腳本中的行數中提取公共部分文本

[英]Extract common part text from number of lines in shell script

我想從給定的行數中提取文本的公共部分。 輸入:

/dir1/dir2/dir3/dir4/a/file1/dir
/dir1/dir2/dir3/dir4/b/file2
/dir1/dir2/dir3/dir4/c/file3/dir
/dir1/dir2/dir3/dir4/a/file4
/dir1/dir2/dir3/dir4/e/file5

預期輸出是dir1到dir4的共同部分。 樣本預期輸出:

/dir1/dir2/dir3/dir4/

到目前為止我嘗試過的代碼:管道輸入到awk命令然后如下所示

awk '{for(i=1;i<=NF;i++)if($i | sort | uniq -c -ne 1)var = i; break;}

但我無法讓這個工作......我知道我可能在邏輯或我對awk命令的理解上出錯了。 有人能幫忙嗎?

這個最長公共前綴問題的Perl解決方案

perl -le '@a=<>; $p=$a[0]; for (@a){ chop $p while ! /^\\Q$p/ }; print $p' file

從輸入文件的行<>構造數組@a
$p是最長的前綴,它被初始化為數組$a[0]的第一個元素
循環遍歷數組@a的元素
雖然前綴$p不匹配! // ! //開始^當前元素的, chop過的最后一個字符。
\\Q告訴正則表達式引擎忽略任何潛在的元字符
最后,打印前綴$p

輸出:

/dir1/dir2/dir3/dir4/

使用-n替代實現隱式構造循環:

perl -lne 'BEGIN{$p = <>}; chop $p while ! /^\\Q$p/; END{print $p}' file


使用substr()而不是/regex/替代實現

perl -lne 'BEGIN{$p=<>} chop $p while $p ne substr($_,0,length($p)); END{print $p}' file

-n循環遍歷文件的每一行
$_包含當前行內容


使用awk的替代實現:

awk 'NR==1{p=$0} {while(p != substr($0,1,length(p))){p=substr(p,1,length(p)-1)}} END{print p}' file


使用Python的替代實現:

#!/usr/bin/python3
import sys
fp = open(sys.argv[1], 'r')
p = fp.readline()
for line in fp:
    while (line.find(p) != 0):
        p = p[:-1]
print(p)

使用C替代實現:

#include <stdio.h>
#include <string.h>
#define MAXLINE 1000
int main (int argc, char* argv[]) {
    FILE *fp = fopen(argv[1], "r");
    char p[MAXLINE];
    char line[MAXLINE];
    fgets(line, MAXLINE, fp);
    strcpy(p, line);
    while (fgets(line, MAXLINE, fp)) {
        while ( strstr(line, p) != line  &&  strlen(p) > 0 ) {
            p[strlen(p)-1] = '\0';
        }
    }
    printf("%s\n", p);
}

為了好玩,我使用20MB輸入文件和10次運行對各種解決方案進行了基准測試
我的perl解決方案列為a,b,c
在perl 5.20和5.22上測試
使用awk 3.1.5和gawk 4.1.0列出@ karakfa和我的awk解決方案
@ balabhi的shell解決方案也列出了
TL; DR:perl substr()解決方案(c)是腳本語言中最快的,但使用哪種解決方案並不重要

                 Rate awk_karakfa gawk_karakfa perl_5.20_b perl_5.22_b perl_5.22_a perl_5.20_a   awk gawk python_3.4.2 shell_balabhi perl_5.22_c perl_5.20_c    c
awk_karakfa   0.618/s          --         -12%        -46%        -51%        -56%        -58%  -58% -80%         -81%          -82%        -85%        -86% -98%
gawk_karakfa  0.701/s         13%           --        -38%        -44%        -50%        -52%  -52% -77%         -79%          -80%        -83%        -84% -97%
perl_5.20_b    1.14/s         84%          62%          --        -10%        -19%        -22%  -22% -63%         -65%          -67%        -72%        -74% -96%
perl_5.22_b    1.26/s        104%          80%         11%          --        -11%        -13%  -13% -59%         -61%          -63%        -69%        -71% -95%
perl_5.22_a    1.41/s        128%         101%         24%         12%          --         -3%   -3% -55%         -57%          -59%        -65%        -68% -95%
perl_5.20_a    1.46/s        135%         108%         28%         15%          3%          --   -0% -53%         -55%          -58%        -64%        -67% -95%
awk            1.46/s        136%         108%         28%         15%          3%          0%    -- -53%         -55%          -58%        -64%        -67% -95%
gawk           3.11/s        402%         343%        173%        146%        120%        113%  113%   --          -5%          -10%        -23%        -30% -89%
python_3.4.2   3.27/s        428%         366%        187%        159%        131%        125%  124%   5%           --           -5%        -19%        -26% -88%
shell_balabhi  3.45/s        458%         392%        203%        173%        144%        137%  137%  11%           6%            --        -15%        -22% -88%
perl_5.22_c    4.05/s        555%         477%        256%        221%        187%        178%  178%  30%          24%           17%          --         -8% -85%
perl_5.20_c    4.41/s        612%         528%        287%        249%        212%        203%  202%  42%          35%           28%          9%          -- -84%
c              27.8/s       4392%        3861%       2342%       2100%       1867%       1808% 1806% 794%         750%          706%        586%        531%   --

再次提交,因為縮進在最后一個答案中搞砸了。 Bash腳本解決方案。

inf=$1
num=`wc -l $inf | awk '{print $1}'`
echo num=$num    
pfx=`sed -n '1p' $inf`
mat=`grep $pfx $inf | wc -l`
echo mat=$mat    
while [ $mat -ne $num ]    
do
    pfx=`dirname $pfx`/
    mat=`grep $pfx $inf | wc -l`
    echo mat=$mat    
done
echo pfx=$pfx    

拯救!

 awk -F/ 'NR==1{w=split($0,base,FS); next} 
               {for(i=1;i<=w;i++) 
                   if(base[i]!=$i) 
                       {w=i; next}
               } 
            END{for(i=1;i<w;i++) 
                   printf base[i] FS; 
                   print ""
               }' file

描述:從FS分隔的第一行構造一個基本數組,保持大小為w(寬度)。 比賽最多可以是w。 對於每行比較最多2個字段,直到發生不匹配,更新w。 全部完成后打印匹配的字段。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM