[英]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.