So drucken SieZeilen vor undZeilen nachZeile

So drucken SieZeilen vor undZeilen nachZeile

Die gestellte FrageHierfragt vor und nach dem Mustervergleich nach einigen Zeilen.

Aber hier ist das Ziel, eine Zeilennummer zu nehmen und einige Zeilen davor und danach aus einer Datei zu holen

Z.B:

seq 10
1
2
3
4
5
6
7
8
9
10

Wenn die Zeilennummer 6 ist, sollten 4 Zahlen vor dieser Zeile und 3 Zahlen nach dieser Zeile angegeben werden. Das ist

2
3
4
5
6
7
8
9

Antwort1

z=6   # focus line
x=4   # lines before
y=3   # lines after

start=$(( z - x ))
end=$(( z + y ))

Verwendung von sed:

seq 10 | sed -n "$start,${end}p"
2
3
4
5
6
7
8
9

Dabei wird einfach der print( p)-Befehl sedmit einem expliziten Zeilenbereich zum Drucken verwendet. Die anderen Zeilen werden mit ignoriert -n.

Verwendung von awk:

seq 10 | awk -v start="$start" -v end="$end" 'NR >= start { print } NR >= end { exit }'
2
3
4
5
6
7
8
9

Dies ähnelt der Antwort von Stéphane Chazelas, ist jedoch in implementiert. awkDas Skript beginnt mit der Ausgabe der Eingabezeilen, nachdem es starteine bestimmte Anzahl von Zeilen gelesen hat. Bei endeiner bestimmten Anzahl von Zeilen wird das Skript beendet.

Bei beiden Alternativen wird ein Teil der Eingabedaten angezeigt, beginnend mit xden Zeilen vor der Zeile zund endend ymit den Zeilen nach der Zeile z.

Antwort2

Mit POSIX-Shells:

$ before=4 after=3 line=6
$ seq 10 | sed "$((line-before)),\$!d; $((line+after))q"
2
3
4
5
6
7
8
9

Wird übersetzt in:

  • Delete jede Zeile außer ( !) aus dem Bereich von derLinie - vorherbis zum Ende ( $).
  • Qauf demZeile + nachZeile

Auf diese Weise brauchen wir nicht weiter zu lesen alsZeile + nachZeile .

Das bedeutet jedoch, dass der Befehl, der seine Daten weiterleitet, sedmit einem SIGPIPE abgebrochen wird, wenn er kurz danach weiterhin Daten sendet, was erwünscht sein kann oder auch nicht.

Antwort3

Nur der Vollständigkeit halber:

$ l=60;seq 100 |head -n$((l+3)) |tail -n+$((l-4))
56
57
58
59
60
61
62
63

Gerüchten und verschiedenen Benchmarks zufolge ist die Kombination aus Head + Tail viel schneller als jedes andere Tool:

$ a=1000000000
$ time seq $a |awk 'NR>=499998{print}NR >= 500004 { exit }' 
499998
499999
500000
500001
500002
500003

real    0m0.158s
user    0m0.152s
sys 0m0.004s

$ time seq $a |sed -n "499998,500003p"
499998
499999
500000
500001
500002
500003

real    1m30.249s
user    1m21.284s
sys 0m12.312s

$ time seq $a |sed "$((500000-2)),\$!d; $((500000+3))q"  #Stephan's Solution
499998
499999
500000
500001
500002
500003

real    0m0.052s
user    0m0.044s
sys 0m0.004s

$ time seq $a |head -n$((500000+3)) |tail -n+$((500000-2))
499998
499999
500000
500001
500002
500003

real    0m0.024s
user    0m0.024s
sys 0m0.004s

$ time seq $a |sed -n "499998,500003p;500004q"
499998
499999
500000
500001
500002
500003

real    0m0.056s
user    0m0.048s
sys 0m0.004s

Antwort4

# define line range constants
before=4
  line=6
 after=3

# setup the sed commands s.t. pattern space holds $before number
# of lines before we hit the line number $line and $after after
s='$!N'
p=`seq -s "$s"   "$before"`
a=`seq -s "$s" 0 "$after"`

N=${p//[0-9]/;}
n=${a//[0-9]/;}

# main...
seq 10 |
sed -e "
   1{ $N }
   \$d;N
   $line!D
   $n;q
"

Eine andere Methode besteht darin, die Datei zu schlürfen und FSauf \nso einzustellen, dass die Felder (jetzt Zeilen) in sind @F. Was bleibt, ist, sie um die 6. Zeile und 4 Elemente davor und 3 Zeilen danach aufzuteilen:

perl -alF\\n -0777ne '$,=$\;print @F[6-4-1..6+3-1]' yourfile

Ergebnisse

2
3
4
5
6
7
8
9

verwandte Informationen