Ich habe eine Datei mit Daten, die ich speichere. Nun möchte ich meine Ergebnisse in eine neue Datei ausdrucken.
Nehmen wir zum Beispiel dieses 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 übernehmen? Die Ausgabe würde ungefähr so aussehen:
Ethernet
t6 ad
Ist das möglich? Ich möchte die Linie und die Von-Position zu dieser Position setzen.
Antwort1
Hier ist ein sed
Ansatz:
$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file
Ethernet
t6 a
Erläuterung
Das -n
unterdrückt die normale Ausgabe (normalerweise wird jede Eingabezeile gedruckt), so dass nur gedruckt wird, wenn dies angefordert wird. Das -E
aktiviert erweiterte reguläre Ausdrücke.
Das sed
Skript hat zwei Befehle, die beide den Substitutionsoperator ( s/original/replacement/
) verwenden. Der 1s/.{11}(.{8}).*/\1/p
wird nur in der 1. Zeile ausgeführt (das macht der 1s
) und gleicht die ersten 11 Zeichen der Zeile ab ( .{11}
), dannerfasstdie nächsten 8 ( (.{8})
, die Klammern sind eine „Erfassungsgruppe“) und dann alles andere bis zum Ende der Zeile ( .*
). All dies wird durch das ersetzt, was in der Erfassungsgruppe war ( \1
; wenn es eine zweite Erfassungsgruppe gäbe, wäre es \2
usw.). Schließlich bewirkt das p
am 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 basiert im Wesentlichen auf der gleichen Idee, außer dass er nur in der 3. Zeile ( ) ausgeführt wird 3s
und die 4 Zeichen ab der 4. Zeile beibehält.
Sie können dasselbe auch mit tun 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 -ne
bedeutet „liest die Eingabedatei Zeile für Zeile und wendet das von angegebene Skript -e
auf jede Zeile an.“ Das Skript hat dieselbe Grundidee wie zuvor. Die $.
Variable enthält die aktuelle Zeilennummer, daher prüfen wir, ob die Zeilennummer entweder 1
oder ist 3
, und führen in diesem Fall die Ersetzung aus, andernfalls überspringen wir. Daher print
wird das nur für diese beiden Zeilen ausgeführt, da alle anderen übersprungen werden.
Natürlich ist das Perl, alsoZEITSCHRIFT:
$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file
Ethernet
t6 a
Erläuterung
Hier -a
bedeutet „teile jede Eingabezeile in das durch angegebene Zeichen auf -F
und speichere es als Array“ @F
. Da das angegebene Zeichen leer ist, wird hierdurch jedes Zeichen der Eingabezeile als Element in gespeichert @F
. Dann drucken wir die Elemente 11-19 (Arrays beginnen bei zu zählen 0
) für die 1. Zeile und 3-7 für die 3.
Antwort2
awk-Ansatz:
$ awk 'NR==1{print substr($0,12,8)};NR==3{print substr($0,4,4)}' input.txt
Ethernet
t6 a
Wird verwendet NR
, um die Zeilennummer (in der AWK-Terminologie - Datensatznummer) zu bestimmen und dementsprechend einen Teilstring der Zeile zu drucken. substr()
Die Funktion hat das 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
Dabei wird <
ein Shell-Operator verwendet, um den Eingabestrom von der Eingabedatei zum Python-Prozess umzuleiten. Beachten Sie, dass Zeichenfolgen in Python 0-indiziert sind, Sie müssen daher die gewünschten Zeichenzahlen alle um 1 verschieben.
tragbare Shell-Methode
Dies funktioniert in ksh
, dash
, bash
. Basiert nur auf Shell-Dienstprogrammen, nichts Externem.
#!/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 so funktioniert es:
$ ./get_line_substrings.sh input.txt
Ethernet
t6 ad