Как печататьстроки до истроки послей строка

Как печататьстроки до истроки послей строка

Заданный вопросздесьзапрашивает несколько строк до и после сопоставления с образцом.

Но здесь цель — взять номер строки и извлечь из файла несколько строк до и после него.

НАПРИМЕР:

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

Если номер строки 6, то должно быть 4 цифры до этой строки и 3 цифры после этой строки. То есть

2
3
4
5
6
7
8
9

решение1

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

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

С использованием sed:

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

pЭто просто использует команду print ( ) sedс явным диапазоном строк для печати. ​​Остальные строки игнорируются с помощью -n.

С использованием awk:

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

Это похоже на ответ Стефана Шазеля, но реализовано в awk; скрипт начинает выводить входные строки после прочтения startопределенного количества строк. При endдостижении определенного количества строк скрипт завершает работу.

Оба варианта будут отображать часть входных данных, начиная со xстрок, предшествующих строке, zи заканчивая yстроками после строки z.

решение2

С оболочками POSIX:

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

Переводится как:

  • гудалить любую строку, кроме ( !) из диапазона отлиния - передй до конца ( $).
  • дуит настрока + послей строка

Таким образом, мы даже не будем читать дальшестрока + послей строка.

Однако это означает, что команда, передающая данные, sedбудет прервана с помощью SIGPIPE, если она продолжит отправлять данные вскоре после этого, что может быть как желательным, так и нежелательным.

решение3

Просто для полноты картины:

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

Слухи и различные тесты говорят о том, что комбинация «голова + хвост» намного быстрее, чем любой другой инструмент:

$ 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

решение4

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

Другой метод — это выжать файл и установить FSтак \n, чтобы поля (теперь строки) были в @F. Остается только разрезать его по 6-й строке и 4 элементам до и 3 строкам после:

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

Полученные результаты

2
3
4
5
6
7
8
9

Связанный контент