/ / Wyodrębnij tekst części wspólnej z liczby wierszy w skrypcie powłoki - bash, shell, awk

Wyodrębnij tekst części wspólnej z liczby wierszy w skrypcie powłoki - bash, shell, awk

Chcę wyodrębnić część wspólną tekstu z zadanej liczby linii. Wkład:

/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

Oczekiwany wynik jest częścią wspólną od dir1 do dir4. Przykładowe oczekiwane wyniki:

/dir1/dir2/dir3/dir4/

Co próbowałem do tej pory kod: potoki, które wprowadzają do polecenia awk, a następnie jako belows

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

Ale nie jestem w stanie tego uruchomić. Wiem, że mogłem pomylić się z logiką lub moim zrozumieniem polecenia awk. Czy ktoś może w tym pomóc?

Odpowiedzi:

0 dla odpowiedzi № 1

awk na ratunek!

 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

Opis: Zbuduj macierz bazową z pierwszej linii oddzielonej przez FS, zachowaj rozmiar w (dla szerokości). Mecz może wynosić co najwyżej. Dla każdej linii porównaj maksymalnie 2 pola, aż do wystąpienia niezgodności, zaktualizuj w. Po zakończeniu drukowania wypisz pasujące pola.


2 dla odpowiedzi nr 2

Rozwiązanie Perla dla tego najdłuższego wspólnego problemu z prefiksem

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

Konstruuje tablicę @a z linii <> pliku wejściowego
$p jest najdłuższym prefiksem, który jest inicjowany do pierwszego elementu w tablicy $a[0]
Przeprowadź pętlę przez elementy tablicy @a
Podczas gdy prefiks $p nie pasuje ! // początek ^ obecnego elementu, chop od ostatniego znaku.
Q mówi silnikowi regex, aby ignorował wszelkie potencjalne metaznaki
Na koniec wydrukuj prefiks $p

wydajność:

/dir1/dir2/dir3/dir4/

Alternatywna implementacja za pomocą -n aby niejawnie skonstruować pętlę:

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


Alternatywna implementacja za pomocą substr() zamiast /regex/

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

-n pętle nad każdą linią pliku
$_ zawiera bieżącą zawartość linii


Alternatywna implementacja za pomocą awk:

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


Alternatywne wdrożenie za pomocą Pythona:

#!/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)

Alternatywna implementacja za pomocą 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] = "";
}
}
printf("%sn", p);
}

Dla zabawy przetestowałem różne rozwiązania za pomocą pliku wejściowego 20 MB i 10 przebiegów
Moje rozwiązania perla są wymienione jako a, b, c
Testowane na perlu 5.20 i 5.22
Rozwiązania @karakfa i my awk są również wymienione, używając awk 3.1.5 i gawk 4.1.0
Na liście znajduje się również rozwiązanie powłoki bbalbhi
TL; DR: Perl substr () rozwiązanie (c) był najszybszy wśród języków skryptowych, ale nie ma znaczenia, którego rozwiązania używasz

                 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%   --

1 dla odpowiedzi nr 3

Przesyłam ponownie, ponieważ w ostatniej odpowiedzi wciskano wcięcie. Rozwiązanie skryptu 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