Durchsuchen Sie eine Datei und drucken Sie Text aus bestimmten Zeilen

8

Ich habe eine Datei mit Daten, die ich speichere. Jetzt möchte ich meine Ergebnisse in eine neue Datei drucken.

Nehmen wir zum Beispiel dieses Beispiel 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

Wie kann ich nur Daten vom 12. bis zum 20. Zeichen der ersten Zeile und dann vom 4. bis zum 8. Zeichen der 3. Zeile erfassen? Die Ausgabe würde ungefähr so ​​aussehen:

Ethernet
t6 ad

Ist das möglich? Ich möchte die Linie und von Position zu dieser Position setzen.

Insanebench420
quelle

Antworten:

9

Hier ist ein sedAnsatz:

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

Erläuterung

Das -nunterdrückt die normale Ausgabe (normal ist das Drucken jeder Eingabezeile), so dass nur gedruckt wird, wenn Sie dazu aufgefordert werden. Das -Eermöglicht erweiterte reguläre Ausdrücke.

Das sedSkript verfügt über zwei Befehle, die beide den Substitutionsoperator ( s/original/replacement/) verwenden. Das 1s/.{11}(.{8}).*/\1/pwird nur in der 1. Zeile ausgeführt (das ist, was das 1stut) und wird mit den ersten 11 Zeichen der Zeile ( .{11}) übereinstimmen , dann erfasst es die nächsten 8 ( (.{8})die Klammern sind eine "Erfassungsgruppe") und dann alles andere bis das Ende der Zeile ( .*). All dies wird durch das ersetzt, was sich in der Erfassungsgruppe befand ( \1; wenn es eine zweite Erfassungsgruppe gäbe, wäre dies \2usw.). Schließlich bewirkt das pam Ende ( s/foo/bar/p), dass die Zeile gedruckt wird, nachdem die Ersetzung vorgenommen wurde. Dies führt dazu, dass nur die Ziel-8-Zeichen ausgegeben werden.

Der zweite Befehl ist dieselbe allgemeine Idee, außer dass er nur in der 3. Zeile ( 3s) ausgeführt wird und die 4 Zeichen ab der 4. Zeile beibehalten.


Sie könnten das Gleiche auch tun mit perl:

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

Erläuterung

Das -nebedeutet "Lesen Sie die Eingabedatei zeilenweise und wenden Sie das von -ejeder Zeile angegebene Skript an. Das Skript ist dieselbe Grundidee wie zuvor. Die $.Variable enthält die aktuelle Zeilennummer, daher prüfen wir, ob die Zeilennummer entweder 1oder 3und ist, wenn Führen Sie also die Ersetzung aus, andernfalls überspringen Sie sie. Daher printwird die nur für diese beiden Zeilen ausgeführt, da alle anderen übersprungen werden.


Das ist natürlich Perl, also TIMTOWTDI :

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

Erläuterung

Hier -abedeutet das Mittel "jede Eingabezeile auf das durch angegebene Zeichen teilen -Fund als Array speichern @F. Da das angegebene Zeichen leer ist, wird jedes Zeichen der Eingabezeile als Element in @Fgespeichert. Dann drucken wir die Elemente 11-19 ( Arrays beginnen bei 0) für die 1. Zeile und 3-7 für die 3. Zeile zu zählen.

Terdon
quelle
1

awk Ansatz:

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

Dient NRzum Bestimmen der Zeilennummer (in der awk-Terminologie - Datensatz) und zum entsprechenden Drucken der Teilzeichenfolge der Zeile. substr()Funktion ist im Format

substr(string,starting position,how much offset) 

Python

$ 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

Dies verwendet den <Shell-Operator, um den Eingabestream von der Eingabedatei zum Python-Prozess umzuleiten. Beachten Sie, dass Zeichenfolgen in Python 0-indiziert sind. Daher müssen Sie die gewünschten Zeichennummern um 1 verschieben.

tragbare Shell Weg

Dies funktioniert in ksh, dash, bash. Verlässt sich nur auf Shell-Dienstprogramme, nichts Externes.

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

Und es funktioniert so:

$ ./get_line_substrings.sh input.txt                                                                                                                                   
Ethernet
t6 ad
Sergiy Kolodyazhnyy
quelle