Przejrzyj plik i wydrukuj tekst z określonych wierszy

8

Mam plik z danymi, które zapisuję. Teraz chciałbym wydrukować moje wyniki w nowym pliku.

Weźmy na przykład ten przykład randomlog.log:

Link encap:Ethernet HWaddr 08:00:00:00:00:67
inet addr:10.10.10.10 Bcast:10.10.10.10 Mask:255.255.255.0
inet6 addr: fe80::casf:sdfg:23ra:dg12/64 Scope:Link

Jak mogę pobrać tylko dane od 12 do 20 znaku pierwszego wiersza, a następnie od 4 do 8 znaków 3 wiersza? Dane wyjściowe wyglądałyby mniej więcej tak:

Ethernet
t6 ad

czy to możliwe? Chcę ustawić linię i od pozycji do tej pozycji.

Insanebench420
źródło

Odpowiedzi:

9

Oto sedpodejście:

$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file  
Ethernet
t6 a

Wyjaśnienie

-nWyjście normalne Pomija (normalne jest, aby wydrukować każdą linię wejściowego), tak, że tylko drukuje, gdy kazano. -EUmożliwia rozszerzonych wyrażeń regularnych.

sedSkrypt ma dwa polecenia, zarówno za pomocą operatora podstawienia ( s/original/replacement/). 1s/.{11}(.{8}).*/\1/pBędzie działać tylko na 1 linię (to właśnie 1srobi), i będzie pasował do 1. 11 znaków w wierszu ( .{11}), to rejestruje kolejne 8 ((.{8}) , nawiasy są „grupa capture”), a następnie wszystko inne, aż koniec linii ( .*). Wszystko to zostaje zastąpione tym, co było w grupie przechwytywania ( \1; gdyby istniała druga grupa przechwytywania, byłoby to \2itd.). Wreszcie, pna końcu ( s/foo/bar/p) powoduje wydrukowanie wiersza po dokonaniu podstawienia. Powoduje to, że wyprowadzane są tylko docelowe 8 znaków.

Drugie polecenie to ten sam ogólny pomysł, z tą różnicą, że będzie działało tylko na 3. linii ( 3s) i zachowa 4 znaki począwszy od 4. linii.


Możesz także zrobić to samo perl :

$ perl -ne 'if($.==1){s/.{11}(.{8}).*/\1/}
            elsif($.==3){s/.{3}(.{4}).*/\1/}
            else{next}; print; ' file 
Ethernet
t6 a

Wyjaśnienie

Te -neśrodki „czytać wiersz pliku wejściowego po linii i zastosować skrypt podany przez -edo każdej linii. Scenariusz jest taki sam podstawowy pomysł, jak wcześniej. Na $.zmienna posiada aktualny numer wiersza więc sprawdzić, czy numer linii jest albo 1czy 3, a jeśli więc uruchom podstawienie, w przeciwnym razie pomiń. Dlategoprint będzie uruchamiany tylko dla tych dwóch linii, ponieważ wszystkie inne zostaną pominięte.


Oczywiście jest to Perl, więc TIMTOWTDI :

$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file 
Ethernet 
t6 a

Wyjaśnienie

-aOznacza to, że „podziel każdą linię wejściową na znak podany przez -Fi zapisz jako tablicę @F. Ponieważ podany znak jest pusty, spowoduje to zapisanie każdego znaku linii wejściowej jako elementu @F. Następnie drukujemy elementy 11–19 ( tablice zaczynają się liczyć od 0) dla 1. linii i 3-7 dla 3. linii.

terdon
źródło
1

podejście awk:

$ awk 'NR==1{print substr($0,12,8)};NR==3{print substr($0,4,4)}' input.txt  
Ethernet
t6 a

Używa NRdo określania numeru linii (w terminologii awk - zapis) i odpowiednio wypisuje podciąg linii. substr()funkcja ma format

substr(string,starting position,how much offset) 

Pyton

$ python -c 'import sys                                                                                                                                                
> for index,line in enumerate(sys.stdin,1):                                                                                                                            
>     if index == 1:
>          print line[11:19]
>     if index == 3:
>          print line[3:7]' < input.txt
Ethernet
t6 a

To używa < operatora powłoki do przekierowania strumienia wejściowego do procesu python z pliku wejściowego. Zauważ, że ciągi w pythonie mają indeks 0, dlatego musisz przesunąć wszystkie pożądane liczby znaków o 1.

przenośny sposób powłoki

To działa w ksh, dash, bash. Opiera się tylko na narzędziach powłoki, nic zewnętrznego.

#!/bin/sh

rsubstr(){
    i=0;
    while [ $i -lt  $2 ];
    do
        rmcount="${rmcount}?"
        i=$(($i+1))
    done;
    echo "${1#$rmcount}"
}

lsubstr(){
    printf "%.${2}s\n" "$1"
}

line_handler(){
    case $2 in
        1) lsubstr "$(rsubstr "$1" 11)" 8 ;;
        3) lsubstr "$(rsubstr "$1" 3)" 5 ;;
    esac
}

readlines(){
    line_count=1
    while IFS= read -r line;
    do
        line_handler "$line" "$line_count"
        line_count=$(($line_count+1))
    done < $1
}

readlines "$1"

I działa tak:

$ ./get_line_substrings.sh input.txt                                                                                                                                   
Ethernet
t6 ad
Sergiy Kolodyazhnyy
źródło